diff --git a/.github/codeql-config.yml b/.github/codeql-config.yml index 0d324d49dc0689..d042ed96096955 100644 --- a/.github/codeql-config.yml +++ b/.github/codeql-config.yml @@ -2,4 +2,5 @@ name: CodeQL config paths-ignore: - test - - deps/v8/test + - deps + - benchmark diff --git a/.github/workflows/auto-start-ci.yml b/.github/workflows/auto-start-ci.yml index 97d9c9482b2754..2588bc82da3f66 100644 --- a/.github/workflows/auto-start-ci.yml +++ b/.github/workflows/auto-start-ci.yml @@ -50,7 +50,7 @@ jobs: persist-credentials: false - name: Install Node.js - uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e # v4.3.0 + uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 with: node-version: ${{ env.NODE_VERSION }} diff --git a/.github/workflows/build-tarball.yml b/.github/workflows/build-tarball.yml index a784b43cfc6268..c5911684070fba 100644 --- a/.github/workflows/build-tarball.yml +++ b/.github/workflows/build-tarball.yml @@ -46,7 +46,7 @@ jobs: with: persist-credentials: false - name: Set up Python ${{ env.PYTHON_VERSION }} - uses: actions/setup-python@8d9ed9ac5c53483de85588cdf95a591a75ab9f55 # v5.5.0 + uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 with: python-version: ${{ env.PYTHON_VERSION }} - name: Set up sccache @@ -76,7 +76,7 @@ jobs: with: persist-credentials: false - name: Set up Python ${{ env.PYTHON_VERSION }} - uses: actions/setup-python@8d9ed9ac5c53483de85588cdf95a591a75ab9f55 # v5.5.0 + uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 with: python-version: ${{ env.PYTHON_VERSION }} - name: Set up sccache @@ -86,7 +86,7 @@ jobs: - name: Environment Information run: npx envinfo - name: Download tarball - uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e # v4.2.1 + uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 with: name: tarballs path: tarballs diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index da80832102026e..191cfc5e5dfddc 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -27,15 +27,15 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@6bb031afdd8eb862ea3fc1848194185e076637e5 # v3.28.11 + uses: github/codeql-action/init@ff0a06e83cb2de871e5a09832bc6a81e7276941f # v3.28.18 with: languages: ${{ matrix.language }} config-file: ./.github/codeql-config.yml - name: Autobuild - uses: github/codeql-action/autobuild@6bb031afdd8eb862ea3fc1848194185e076637e5 # v3.28.11 + uses: github/codeql-action/autobuild@ff0a06e83cb2de871e5a09832bc6a81e7276941f # v3.28.18 - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@6bb031afdd8eb862ea3fc1848194185e076637e5 # v3.28.11 + uses: github/codeql-action/analyze@ff0a06e83cb2de871e5a09832bc6a81e7276941f # v3.28.18 with: category: /language:${{matrix.language}} diff --git a/.github/workflows/commit-lint.yml b/.github/workflows/commit-lint.yml index f6273871a8a26b..4cd44c6d18538f 100644 --- a/.github/workflows/commit-lint.yml +++ b/.github/workflows/commit-lint.yml @@ -23,7 +23,7 @@ jobs: persist-credentials: false - run: git reset HEAD^2 - name: Install Node.js - uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e # v4.3.0 + uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 with: node-version: ${{ env.NODE_VERSION }} - name: Validate commit message diff --git a/.github/workflows/commit-queue.yml b/.github/workflows/commit-queue.yml index 556843635dd676..e9e151ba3d287c 100644 --- a/.github/workflows/commit-queue.yml +++ b/.github/workflows/commit-queue.yml @@ -72,7 +72,7 @@ jobs: # Install dependencies - name: Install Node.js - uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e # v4.3.0 + uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 with: node-version: ${{ env.NODE_VERSION }} - name: Install @node-core/utils diff --git a/.github/workflows/coverage-linux-without-intl.yml b/.github/workflows/coverage-linux-without-intl.yml index a1f8f060ddab13..956058c6889e4c 100644 --- a/.github/workflows/coverage-linux-without-intl.yml +++ b/.github/workflows/coverage-linux-without-intl.yml @@ -45,14 +45,15 @@ permissions: jobs: coverage-linux-without-intl: - if: github.event.pull_request.draft == false + # Disabled because "Report JS" step was crashing. + if: false runs-on: ubuntu-24.04 steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: persist-credentials: false - name: Set up Python ${{ env.PYTHON_VERSION }} - uses: actions/setup-python@8d9ed9ac5c53483de85588cdf95a591a75ab9f55 # v5.5.0 + uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 with: python-version: ${{ env.PYTHON_VERSION }} - name: Set up sccache @@ -79,6 +80,6 @@ jobs: - name: Clean tmp run: rm -rf coverage/tmp && rm -rf out - name: Upload - uses: codecov/codecov-action@0565863a31f2c772f9f0395002a31e3f06189574 # v5.4.0 + uses: codecov/codecov-action@18283e04ce6e62d37312384ff67231eb8fd56d24 # v5.4.3 with: directory: ./coverage diff --git a/.github/workflows/coverage-linux.yml b/.github/workflows/coverage-linux.yml index 9305d5f02cad6f..3a7ad75d375875 100644 --- a/.github/workflows/coverage-linux.yml +++ b/.github/workflows/coverage-linux.yml @@ -45,14 +45,15 @@ permissions: jobs: coverage-linux: - if: github.event.pull_request.draft == false + # Disabled because "Report JS" step was crashing. + if: false runs-on: ubuntu-24.04 steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: persist-credentials: false - name: Set up Python ${{ env.PYTHON_VERSION }} - uses: actions/setup-python@8d9ed9ac5c53483de85588cdf95a591a75ab9f55 # v5.5.0 + uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 with: python-version: ${{ env.PYTHON_VERSION }} - name: Set up sccache @@ -79,6 +80,6 @@ jobs: - name: Clean tmp run: rm -rf coverage/tmp && rm -rf out - name: Upload - uses: codecov/codecov-action@0565863a31f2c772f9f0395002a31e3f06189574 # v5.4.0 + uses: codecov/codecov-action@18283e04ce6e62d37312384ff67231eb8fd56d24 # v5.4.3 with: directory: ./coverage diff --git a/.github/workflows/coverage-windows.yml b/.github/workflows/coverage-windows.yml index 0ada43321eb5ed..5acb24cfc707df 100644 --- a/.github/workflows/coverage-windows.yml +++ b/.github/workflows/coverage-windows.yml @@ -49,7 +49,7 @@ jobs: with: persist-credentials: false - name: Set up Python ${{ env.PYTHON_VERSION }} - uses: actions/setup-python@8d9ed9ac5c53483de85588cdf95a591a75ab9f55 # v5.5.0 + uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 with: python-version: ${{ env.PYTHON_VERSION }} - name: Install deps @@ -71,6 +71,6 @@ jobs: - name: Clean tmp run: npx rimraf ./coverage/tmp - name: Upload - uses: codecov/codecov-action@0565863a31f2c772f9f0395002a31e3f06189574 # v5.4.0 + uses: codecov/codecov-action@18283e04ce6e62d37312384ff67231eb8fd56d24 # v5.4.3 with: directory: ./coverage diff --git a/.github/workflows/create-release-proposal.yml b/.github/workflows/create-release-proposal.yml index 0ce9a40541c87e..58cf5a0bba55f6 100644 --- a/.github/workflows/create-release-proposal.yml +++ b/.github/workflows/create-release-proposal.yml @@ -40,7 +40,7 @@ jobs: # Install dependencies - name: Install Node.js - uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e # v4.3.0 + uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 with: node-version: ${{ env.NODE_VERSION }} diff --git a/.github/workflows/daily-wpt-fyi.yml b/.github/workflows/daily-wpt-fyi.yml index f8664adb1eb582..3cc6e6c54cd28c 100644 --- a/.github/workflows/daily-wpt-fyi.yml +++ b/.github/workflows/daily-wpt-fyi.yml @@ -39,7 +39,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Set up Python ${{ env.PYTHON_VERSION }} - uses: actions/setup-python@8d9ed9ac5c53483de85588cdf95a591a75ab9f55 # v5.5.0 + uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 with: python-version: ${{ env.PYTHON_VERSION }} - name: Environment Information @@ -51,7 +51,7 @@ jobs: run: echo "NIGHTLY=$(curl -s https://nodejs.org/download/nightly/index.json | jq -r '[.[] | select(.files[] | contains("linux-x64"))][0].version')" >> $GITHUB_ENV - name: Install Node.js id: setup-node - uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e # v4.3.0 + uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 with: node-version: ${{ env.NIGHTLY || matrix.node-version }} check-latest: true diff --git a/.github/workflows/daily.yml b/.github/workflows/daily.yml index b6ba485f48f072..ae2b7a577f7b0f 100644 --- a/.github/workflows/daily.yml +++ b/.github/workflows/daily.yml @@ -19,7 +19,7 @@ jobs: with: persist-credentials: false - name: Use Node.js ${{ env.NODE_VERSION }} - uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e # v4.3.0 + uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 with: node-version: ${{ env.NODE_VERSION }} - name: Environment Information diff --git a/.github/workflows/doc.yml b/.github/workflows/doc.yml index c8a80d59e30948..1793edd12ce261 100644 --- a/.github/workflows/doc.yml +++ b/.github/workflows/doc.yml @@ -28,7 +28,7 @@ jobs: with: persist-credentials: false - name: Use Node.js ${{ env.NODE_VERSION }} - uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e # v4.3.0 + uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 with: node-version: ${{ env.NODE_VERSION }} - name: Environment Information diff --git a/.github/workflows/find-inactive-collaborators.yml b/.github/workflows/find-inactive-collaborators.yml index 595751b6a455a9..269bc2db172be8 100644 --- a/.github/workflows/find-inactive-collaborators.yml +++ b/.github/workflows/find-inactive-collaborators.yml @@ -25,7 +25,7 @@ jobs: persist-credentials: false - name: Use Node.js ${{ env.NODE_VERSION }} - uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e # v4.3.0 + uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 with: node-version: ${{ env.NODE_VERSION }} diff --git a/.github/workflows/find-inactive-tsc.yml b/.github/workflows/find-inactive-tsc.yml index e553a5145128c7..9e294994ba8180 100644 --- a/.github/workflows/find-inactive-tsc.yml +++ b/.github/workflows/find-inactive-tsc.yml @@ -34,7 +34,7 @@ jobs: repository: nodejs/TSC - name: Use Node.js ${{ env.NODE_VERSION }} - uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e # v4.3.0 + uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 with: node-version: ${{ env.NODE_VERSION }} diff --git a/.github/workflows/lint-release-proposal.yml b/.github/workflows/lint-release-proposal.yml index 9d8ba5998a7a5c..88bbd5d4e9b068 100644 --- a/.github/workflows/lint-release-proposal.yml +++ b/.github/workflows/lint-release-proposal.yml @@ -20,6 +20,7 @@ jobs: lint-release-commit: runs-on: ubuntu-latest permissions: + contents: read pull-requests: read steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 diff --git a/.github/workflows/linters.yml b/.github/workflows/linters.yml index 1a97aeec9fe5b9..b3db61eca640f7 100644 --- a/.github/workflows/linters.yml +++ b/.github/workflows/linters.yml @@ -29,7 +29,7 @@ jobs: with: persist-credentials: false - name: Use Node.js ${{ env.NODE_VERSION }} - uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e # v4.3.0 + uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 with: node-version: ${{ env.NODE_VERSION }} - name: Environment Information @@ -44,7 +44,7 @@ jobs: with: persist-credentials: false - name: Set up Python ${{ env.PYTHON_VERSION }} - uses: actions/setup-python@8d9ed9ac5c53483de85588cdf95a591a75ab9f55 # v5.5.0 + uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 with: python-version: ${{ env.PYTHON_VERSION }} - name: Environment Information @@ -60,11 +60,11 @@ jobs: fetch-depth: 0 persist-credentials: false - name: Use Node.js ${{ env.NODE_VERSION }} - uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e # v4.3.0 + uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 with: node-version: ${{ env.NODE_VERSION }} - name: Set up Python ${{ env.PYTHON_VERSION }} - uses: actions/setup-python@8d9ed9ac5c53483de85588cdf95a591a75ab9f55 # v5.5.0 + uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 with: python-version: ${{ env.PYTHON_VERSION }} - name: Environment Information @@ -97,7 +97,7 @@ jobs: with: persist-credentials: false - name: Use Node.js ${{ env.NODE_VERSION }} - uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e # v4.3.0 + uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 with: node-version: ${{ env.NODE_VERSION }} - name: Environment Information @@ -122,7 +122,7 @@ jobs: with: persist-credentials: false - name: Set up Python ${{ env.PYTHON_VERSION }} - uses: actions/setup-python@8d9ed9ac5c53483de85588cdf95a591a75ab9f55 # v5.5.0 + uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 with: python-version: ${{ env.PYTHON_VERSION }} - name: Environment Information @@ -139,7 +139,7 @@ jobs: with: persist-credentials: false - name: Use Python ${{ env.PYTHON_VERSION }} - uses: actions/setup-python@8d9ed9ac5c53483de85588cdf95a591a75ab9f55 # v5.5.0 + uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 with: python-version: ${{ env.PYTHON_VERSION }} - name: Environment Information diff --git a/.github/workflows/notify-on-push.yml b/.github/workflows/notify-on-push.yml index 14b184deb515c2..bdda058f104795 100644 --- a/.github/workflows/notify-on-push.yml +++ b/.github/workflows/notify-on-push.yml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Slack Notification - uses: rtCamp/action-slack-notify@c33737706dea87cd7784c687dadc9adf1be59990 # 2.3.2 + uses: rtCamp/action-slack-notify@e31e87e03dd19038e411e38ae27cbad084a90661 # 2.3.3 env: SLACK_COLOR: '#DE512A' SLACK_ICON: https://github.com/nodejs.png?size=48 @@ -32,6 +32,7 @@ jobs: if: github.repository == 'nodejs/node' runs-on: ubuntu-latest permissions: + contents: read pull-requests: write steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 @@ -56,7 +57,7 @@ jobs: GH_TOKEN: ${{ github.token }} - name: Slack Notification if: ${{ env.INVALID_COMMIT_MESSAGE }} - uses: rtCamp/action-slack-notify@c33737706dea87cd7784c687dadc9adf1be59990 # 2.3.2 + uses: rtCamp/action-slack-notify@e31e87e03dd19038e411e38ae27cbad084a90661 # 2.3.3 env: SLACK_COLOR: '#DE512A' SLACK_ICON: https://github.com/nodejs.png?size=48 diff --git a/.github/workflows/notify-on-review-wanted.yml b/.github/workflows/notify-on-review-wanted.yml index b4e3490f31f3d6..96eee3096d8b69 100644 --- a/.github/workflows/notify-on-review-wanted.yml +++ b/.github/workflows/notify-on-review-wanted.yml @@ -33,7 +33,7 @@ jobs: fi - name: Slack Notification - uses: rtCamp/action-slack-notify@c33737706dea87cd7784c687dadc9adf1be59990 # 2.3.2 + uses: rtCamp/action-slack-notify@e31e87e03dd19038e411e38ae27cbad084a90661 # 2.3.3 env: MSG_MINIMAL: actions url SLACK_COLOR: '#3d85c6' diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index 82bbdcfe4551bc..574703f4b0227b 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -33,7 +33,7 @@ jobs: steps: - name: Harden Runner - uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0 + uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs @@ -43,7 +43,7 @@ jobs: persist-credentials: false - name: Run analysis - uses: ossf/scorecard-action@f49aabe0b5af0936a0987cfb85d86b75731b0186 # v2.4.1 + uses: ossf/scorecard-action@05b42c624433fc40578a4040d5cf5e36ddca8cde # v2.4.2 with: results_file: results.sarif results_format: sarif @@ -73,6 +73,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: Upload to code-scanning - uses: github/codeql-action/upload-sarif@1b549b9259bda1cb5ddde3b41741a82a2d15a841 # v3.28.13 + uses: github/codeql-action/upload-sarif@ff0a06e83cb2de871e5a09832bc6a81e7276941f # v3.28.18 with: sarif_file: results.sarif diff --git a/.github/workflows/test-internet.yml b/.github/workflows/test-internet.yml index 64229dcffc6ed5..7d25113c024f78 100644 --- a/.github/workflows/test-internet.yml +++ b/.github/workflows/test-internet.yml @@ -48,7 +48,7 @@ jobs: with: persist-credentials: false - name: Set up Python ${{ env.PYTHON_VERSION }} - uses: actions/setup-python@8d9ed9ac5c53483de85588cdf95a591a75ab9f55 # v5.5.0 + uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 with: python-version: ${{ env.PYTHON_VERSION }} - name: Environment Information diff --git a/.github/workflows/test-linux.yml b/.github/workflows/test-linux.yml index 2266d0da067cdd..789689c25cd4bf 100644 --- a/.github/workflows/test-linux.yml +++ b/.github/workflows/test-linux.yml @@ -3,6 +3,7 @@ name: Test Linux on: pull_request: paths-ignore: + - .mailmap - README.md - .github/** - '!.github/workflows/test-linux.yml' @@ -14,6 +15,7 @@ on: - v[0-9]+.x-staging - v[0-9]+.x paths-ignore: + - .mailmap - README.md - .github/** - '!.github/workflows/test-linux.yml' @@ -46,7 +48,7 @@ jobs: persist-credentials: false path: node - name: Set up Python ${{ env.PYTHON_VERSION }} - uses: actions/setup-python@8d9ed9ac5c53483de85588cdf95a591a75ab9f55 # v5.5.0 + uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 with: python-version: ${{ env.PYTHON_VERSION }} - name: Set up sccache diff --git a/.github/workflows/test-macos.yml b/.github/workflows/test-macos.yml index 53329afd930b46..c74e200acb0295 100644 --- a/.github/workflows/test-macos.yml +++ b/.github/workflows/test-macos.yml @@ -52,7 +52,7 @@ jobs: persist-credentials: false path: node - name: Set up Python ${{ env.PYTHON_VERSION }} - uses: actions/setup-python@8d9ed9ac5c53483de85588cdf95a591a75ab9f55 # v5.5.0 + uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 with: python-version: ${{ env.PYTHON_VERSION }} - name: Set up Xcode ${{ env.XCODE_VERSION }} diff --git a/.github/workflows/tools.yml b/.github/workflows/tools.yml index 6e60911d5d95b8..4004304746d651 100644 --- a/.github/workflows/tools.yml +++ b/.github/workflows/tools.yml @@ -303,7 +303,7 @@ jobs: persist-credentials: false - name: Set up Python ${{ env.PYTHON_VERSION }} if: matrix.id == 'icu' && (github.event_name == 'schedule' || inputs.id == 'all' || inputs.id == matrix.id) - uses: actions/setup-python@8d9ed9ac5c53483de85588cdf95a591a75ab9f55 # v5.5.0 + uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 with: python-version: ${{ env.PYTHON_VERSION }} - run: ${{ matrix.run }} diff --git a/.github/workflows/update-v8.yml b/.github/workflows/update-v8.yml index a53f28ba4baf4c..0b290e41ada4a0 100644 --- a/.github/workflows/update-v8.yml +++ b/.github/workflows/update-v8.yml @@ -30,7 +30,7 @@ jobs: ~/.npm key: ${{ runner.os }}-build-${{ env.cache-name }} - name: Install Node.js - uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e # v4.3.0 + uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 with: node-version: ${{ env.NODE_VERSION }} - name: Install @node-core/utils diff --git a/.github/workflows/update-wpt.yml b/.github/workflows/update-wpt.yml index 30ac409df1b5b8..57eacd91d8c908 100644 --- a/.github/workflows/update-wpt.yml +++ b/.github/workflows/update-wpt.yml @@ -32,7 +32,7 @@ jobs: persist-credentials: false - name: Install Node.js - uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e # v4.3.0 + uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 with: node-version: ${{ env.NODE_VERSION }} diff --git a/.mailmap b/.mailmap index a060a422d49cce..ec877b4c767a83 100644 --- a/.mailmap +++ b/.mailmap @@ -204,6 +204,7 @@ George Adams Gerhard Stöbich Gibson Fahnestock Gil Pedersen +Giovanni Bucci Graham Fairweather Greg Sabia Tucker Gregor Martynus @@ -270,6 +271,7 @@ John McGuirk John Musgrave Johnny Ray Austin Jon Tippens +Jonas Badalic Jonas Pfenniger Jonathan Gourlay Jonathan Ong diff --git a/BUILDING.md b/BUILDING.md index 4b890031c23fd6..cedf2cb5e88d1e 100644 --- a/BUILDING.md +++ b/BUILDING.md @@ -124,6 +124,7 @@ platforms. This is true regardless of entries in the table below. | SmartOS | x64 | >= 18 | Tier 2 | | | AIX | ppc64be >=power8 | >= 7.2 TL04 | Tier 2 | | | FreeBSD | x64 | >= 13.2 | Experimental | | +| OpenHarmony | arm64 | >= 5.0 | Experimental | | diff --git a/CHANGELOG.md b/CHANGELOG.md index b9e66edc9113c0..43880847dd26ad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -37,7 +37,8 @@ release. -22.16.0
+22.17.0
+22.16.0
22.15.1
22.15.0
22.14.0
diff --git a/Makefile b/Makefile index 9c5b36d088babd..3291a94d2c8d3d 100644 --- a/Makefile +++ b/Makefile @@ -509,16 +509,24 @@ SQLITE_BINDING_SOURCES := \ $(wildcard test/sqlite/*/*.c) # Implicitly depends on $(NODE_EXE), see the build-sqlite-tests rule for rationale. +ifndef NOSQLITE test/sqlite/.buildstamp: $(ADDONS_PREREQS) \ $(SQLITE_BINDING_GYPS) $(SQLITE_BINDING_SOURCES) @$(call run_build_addons,"$$PWD/test/sqlite",$@) +else +test/sqlite/.buildstamp: +endif .PHONY: build-sqlite-tests +ifndef NOSQLITE # .buildstamp needs $(NODE_EXE) but cannot depend on it # directly because it calls make recursively. The parent make cannot know # if the subprocess touched anything so it pessimistically assumes that # .buildstamp is out of date and need a rebuild. build-sqlite-tests: | $(NODE_EXE) test/sqlite/.buildstamp ## Build SQLite tests. +else +build-sqlite-tests: +endif .PHONY: clear-stalled clear-stalled: ## Clear any stalled processes. diff --git a/README.md b/README.md index a199de3cb9aa16..0a7ff9bb1978b7 100644 --- a/README.md +++ b/README.md @@ -180,6 +180,8 @@ For information about the governance of the Node.js project, see **Matteo Collina** <> (he/him) * [mhdawson](https://github.com/mhdawson) - **Michael Dawson** <> (he/him) +* [panva](https://github.com/panva) - + **Filip Skokan** <> (he/him) * [RafaelGSS](https://github.com/RafaelGSS) - **Rafael Gonzaga** <> (he/him) * [RaisinTen](https://github.com/RaisinTen) - @@ -363,6 +365,8 @@ For information about the governance of the Node.js project, see **Jason Zhang** <> (he/him) * [jkrems](https://github.com/jkrems) - **Jan Martin** <> (he/him) +* [JonasBa](https://github.com/JonasBa) - + **Jonas Badalic** <> (he/him) * [joyeecheung](https://github.com/joyeecheung) - **Joyee Cheung** <> (she/her) * [juanarbol](https://github.com/juanarbol) - @@ -399,18 +403,18 @@ For information about the governance of the Node.js project, see **Xuguang Mei** <> (he/him) * [mhdawson](https://github.com/mhdawson) - **Michael Dawson** <> (he/him) -* [mildsunrise](https://github.com/mildsunrise) - - **Alba Mendez** <> (she/her) * [MoLow](https://github.com/MoLow) - **Moshe Atlow** <> (he/him) * [MrJithil](https://github.com/MrJithil) - **Jithil P Ponnan** <> (he/him) * [panva](https://github.com/panva) - - **Filip Skokan** <> (he/him) + **Filip Skokan** <> (he/him) - [Support me](https://github.com/sponsors/panva) * [pimterry](https://github.com/pimterry) - **Tim Perry** <> (he/him) * [pmarchini](https://github.com/pmarchini) - **Pietro Marchini** <> (he/him) +* [puskin](https://github.com/puskin) - + **Giovanni Bucci** <> (he/him) * [Qard](https://github.com/Qard) - **Stephen Belanger** <> (he/him) * [RafaelGSS](https://github.com/RafaelGSS) - @@ -607,6 +611,8 @@ For information about the governance of the Node.js project, see **Mikeal Rogers** <> * [miladfarca](https://github.com/miladfarca) - **Milad Fa** <> (he/him) +* [mildsunrise](https://github.com/mildsunrise) - + **Alba Mendez** <> (she/her) * [misterdjules](https://github.com/misterdjules) - **Julien Gilli** <> * [mmarchini](https://github.com/mmarchini) - diff --git a/benchmark/es/error-stack.js b/benchmark/es/error-stack.js index 3b373dcdae63c8..2cc3321640c5cd 100644 --- a/benchmark/es/error-stack.js +++ b/benchmark/es/error-stack.js @@ -10,7 +10,7 @@ const bench = common.createBenchmark(main, { 'without-sourcemap', 'sourcemap', 'node-modules-without-sourcemap', - 'node-module-sourcemap'], + 'node-modules-sourcemap'], n: [1e5], }); diff --git a/benchmark/fs/bench-cpSync.js b/benchmark/fs/bench-cpSync.js index 5ee11689e47a8e..822036726d198d 100644 --- a/benchmark/fs/bench-cpSync.js +++ b/benchmark/fs/bench-cpSync.js @@ -4,20 +4,56 @@ const common = require('../common'); const fs = require('fs'); const path = require('path'); const tmpdir = require('../../test/common/tmpdir'); -tmpdir.refresh(); const bench = common.createBenchmark(main, { n: [1, 100, 10_000], + dereference: ['true', 'false'], + // When `force` is `true` the `cpSync` function is called twice the second + // time however an `ERR_FS_CP_EINVAL` is thrown, so skip `true` for the time being + // TODO: allow `force` to also be `true` once https://github.com/nodejs/node/issues/58468 is addressed + force: ['false'], }); -function main({ n }) { +function prepareTestDirectory() { + const testDir = tmpdir.resolve(`test-cp-${process.pid}`); + fs.mkdirSync(testDir, { recursive: true }); + + fs.writeFileSync(path.join(testDir, 'source.txt'), 'test content'); + + fs.symlinkSync( + path.join(testDir, 'source.txt'), + path.join(testDir, 'link.txt'), + ); + + return testDir; +} + +function main({ n, dereference, force }) { tmpdir.refresh(); - const options = { recursive: true }; - const src = path.join(__dirname, '../../test/fixtures/copy'); + + const src = prepareTestDirectory(); const dest = tmpdir.resolve(`${process.pid}/subdir/cp-bench-${process.pid}`); + + const options = { + recursive: true, + dereference: dereference === 'true', + force: force === 'true', + }; + + if (options.force) { + fs.cpSync(src, dest, { recursive: true }); + } + bench.start(); for (let i = 0; i < n; i++) { - fs.cpSync(src, dest, options); + if (options.force) { + fs.cpSync(src, dest, options); + } else { + const uniqueDest = tmpdir.resolve( + `${process.pid}/subdir/cp-bench-${process.pid}-${i}`, + ); + fs.cpSync(src, uniqueDest, options); + } } bench.end(n); } diff --git a/benchmark/path/join-posix.js b/benchmark/path/join-posix.js index 2e7836650af455..fe4ea4b4a4724a 100644 --- a/benchmark/path/join-posix.js +++ b/benchmark/path/join-posix.js @@ -16,8 +16,8 @@ function main({ n, paths }) { bench.start(); for (let i = 0; i < n; i++) { - if (i % 3 === 0) { - copy[1] = `${orig}${i}`; + if (i % 5 === 0) { + copy[1] = `${orig}/${i}`; posix.join(...copy); } else { posix.join(...args); diff --git a/benchmark/path/join-win32.js b/benchmark/path/join-win32.js index 3ad1c0c7ba2a61..41899dd9240842 100644 --- a/benchmark/path/join-win32.js +++ b/benchmark/path/join-win32.js @@ -16,8 +16,8 @@ function main({ n, paths }) { bench.start(); for (let i = 0; i < n; i++) { - if (i % 3 === 0) { - copy[1] = `${orig}${i}`; + if (i % 5 === 0) { + copy[1] = `${orig}\\${i}`; win32.join(...copy); } else { win32.join(...args); diff --git a/benchmark/path/normalize-posix.js b/benchmark/path/normalize-posix.js index 3e90bfc21aec46..4318ee0b147eda 100644 --- a/benchmark/path/normalize-posix.js +++ b/benchmark/path/normalize-posix.js @@ -17,7 +17,7 @@ const bench = common.createBenchmark(main, { function main({ n, path }) { bench.start(); for (let i = 0; i < n; i++) { - posix.normalize(i % 3 === 0 ? `${path}${i}` : path); + posix.normalize(i % 5 === 0 ? `${path}/${i}` : path); } bench.end(n); } diff --git a/benchmark/path/normalize-win32.js b/benchmark/path/normalize-win32.js index 33af7953ff547d..289b385d3f65a8 100644 --- a/benchmark/path/normalize-win32.js +++ b/benchmark/path/normalize-win32.js @@ -17,7 +17,7 @@ const bench = common.createBenchmark(main, { function main({ n, path }) { bench.start(); for (let i = 0; i < n; i++) { - win32.normalize(i % 3 === 0 ? `${path}${i}` : path); + win32.normalize(i % 5 === 0 ? `${path}\\${i}` : path); } bench.end(n); } diff --git a/benchmark/path/resolve-posix.js b/benchmark/path/resolve-posix.js index 4881947fe46b6d..edc3593bb7f4d9 100644 --- a/benchmark/path/resolve-posix.js +++ b/benchmark/path/resolve-posix.js @@ -4,23 +4,26 @@ const { posix } = require('path'); const bench = common.createBenchmark(main, { paths: [ + 'empty', '', + '.', ['', ''].join('|'), ['foo/bar', '/tmp/file/', '..', 'a/../subfile'].join('|'), ['a/b/c/', '../../..'].join('|'), + ['/a/b/c/', 'abc'].join('|'), ], n: [1e5], }); function main({ n, paths }) { - const args = paths.split('|'); + const args = paths === 'empty' ? [] : paths.split('|'); const copy = [...args]; - const orig = copy[0]; + const orig = copy[0] ?? ''; bench.start(); for (let i = 0; i < n; i++) { - if (i % 3 === 0) { - copy[0] = `${orig}${i}`; + if (i % 5 === 0) { + copy[0] = `${orig}/${i}`; posix.resolve(...copy); } else { posix.resolve(...args); diff --git a/benchmark/path/resolve-win32.js b/benchmark/path/resolve-win32.js index 822b98c2b86c52..a28f2f43e25314 100644 --- a/benchmark/path/resolve-win32.js +++ b/benchmark/path/resolve-win32.js @@ -4,7 +4,9 @@ const { win32 } = require('path'); const bench = common.createBenchmark(main, { paths: [ + 'empty', '', + '.', ['', ''].join('|'), ['c:/ignore', 'd:\\a/b\\c/d', '\\e.exe'].join('|'), ['c:/blah\\blah', 'd:/games', 'c:../a'].join('|'), @@ -13,14 +15,14 @@ const bench = common.createBenchmark(main, { }); function main({ n, paths }) { - const args = paths.split('|'); + const args = paths === 'empty' ? [] : paths.split('|'); const copy = [...args]; - const orig = copy[0]; + const orig = copy[0] ?? ''; bench.start(); for (let i = 0; i < n; i++) { - if (i % 3 === 0) { - copy[0] = `${orig}${i}`; + if (i % 5 === 0) { + copy[0] = `${orig}\\${i}`; win32.resolve(...copy); } else { win32.resolve(...args); diff --git a/common.gypi b/common.gypi index 393fe32765794f..a73d4401f26d84 100644 --- a/common.gypi +++ b/common.gypi @@ -82,6 +82,7 @@ 'v8_enable_direct_local%': 0, 'v8_enable_map_packing%': 0, 'v8_enable_pointer_compression_shared_cage%': 0, + 'v8_enable_external_code_space%': 0, 'v8_enable_sandbox%': 0, 'v8_enable_v8_checks%': 0, 'v8_enable_zone_compression%': 0, @@ -115,12 +116,13 @@ ['target_arch in "arm ia32 mips mipsel ppc"', { 'v8_enable_pointer_compression': 0, 'v8_enable_31bit_smis_on_64bit_arch': 0, + 'v8_enable_external_code_space': 0, 'v8_enable_sandbox': 0 }], ['target_arch in "ppc64 s390x"', { 'v8_enable_backtrace': 1, }], - ['OS=="linux"', { + ['OS=="linux" or OS=="openharmony"', { 'node_section_ordering_info%': '' }], ['OS == "zos"', { @@ -202,7 +204,7 @@ 'LLVM_LTO': 'YES', }, }], - ['OS=="linux"', { + ['OS=="linux" or OS=="openharmony"', { 'conditions': [ ['node_section_ordering_info!=""', { 'cflags': [ @@ -230,7 +232,7 @@ # frames otherwise, even with --call-graph dwarf. 'cflags': [ '-fno-omit-frame-pointer' ], }], - ['OS=="linux"', { + ['OS=="linux" or OS=="openharmony"', { 'conditions': [ ['enable_pgo_generate=="true"', { 'cflags': ['<(pgo_generate)'], @@ -276,6 +278,9 @@ # Defines these mostly for node-gyp to pickup. 'defines': [ '_GLIBCXX_USE_CXX11_ABI=1', + # This help forks when building Node.js on a 32-bit arch as + # libuv is always compiled with _FILE_OFFSET_BITS=64 + '_FILE_OFFSET_BITS=64' ], # Forcibly disable -Werror. We support a wide range of compilers, it's @@ -455,6 +460,9 @@ ['v8_enable_sandbox == 1', { 'defines': ['V8_ENABLE_SANDBOX',], }], + ['v8_enable_external_code_space == 1', { + 'defines': ['V8_EXTERNAL_CODE_SPACE',], + }], ['v8_deprecation_warnings == 1', { 'defines': ['V8_DEPRECATION_WARNINGS',], }], @@ -495,11 +503,11 @@ 'NOMINMAX', ], }], - [ 'OS in "linux freebsd openbsd solaris aix os400"', { + [ 'OS in "linux freebsd openbsd solaris aix os400 openharmony"', { 'cflags': [ '-pthread' ], 'ldflags': [ '-pthread' ], }], - [ 'OS in "linux freebsd openbsd solaris android aix os400 cloudabi"', { + [ 'OS in "linux freebsd openbsd solaris android aix os400 cloudabi openharmony"', { 'cflags': [ '-Wall', '-Wextra', '-Wno-unused-parameter', ], 'cflags_cc': [ '-fno-rtti', diff --git a/configure.py b/configure.py index 932484674e5b15..4560bac7b8e3c7 100755 --- a/configure.py +++ b/configure.py @@ -46,7 +46,7 @@ parser = argparse.ArgumentParser() valid_os = ('win', 'mac', 'solaris', 'freebsd', 'openbsd', 'linux', - 'android', 'aix', 'cloudabi', 'os400', 'ios') + 'android', 'aix', 'cloudabi', 'os400', 'ios', 'openharmony') valid_arch = ('arm', 'arm64', 'ia32', 'mips', 'mipsel', 'mips64el', 'ppc', 'ppc64', 'x64', 'x86', 'x86_64', 's390x', 'riscv64', 'loong64') valid_arm_float_abi = ('soft', 'softfp', 'hard') @@ -864,6 +864,12 @@ default=None, help='build without NODE_OPTIONS support') +parser.add_argument('--without-sqlite', + action='store_true', + dest='without_sqlite', + default=None, + help='build without SQLite (disables SQLite and Web Stoage API)') + parser.add_argument('--ninja', action='store_true', dest='use_ninja', @@ -1710,7 +1716,15 @@ def configure_v8(o, configs): o['variables']['v8_use_siphash'] = 0 if options.without_siphash else 1 o['variables']['v8_enable_maglev'] = 1 if options.v8_enable_maglev else 0 o['variables']['v8_enable_pointer_compression'] = 1 if options.enable_pointer_compression else 0 - o['variables']['v8_enable_sandbox'] = 1 if options.enable_pointer_compression else 0 + # Using the sandbox requires always allocating array buffer backing stores in the sandbox. + # We currently have many backing stores tied to pointers from C++ land that are not + # even necessarily dynamic (e.g. in static storage) for fast communication between JS and C++. + # Until we manage to get rid of all those, v8_enable_sandbox cannot be used. + # Note that enabling pointer compression without enabling sandbox is unsupported by V8, + # so this can be broken at any time. + o['variables']['v8_enable_sandbox'] = 0 + o['variables']['v8_enable_pointer_compression_shared_cage'] = 1 if options.enable_pointer_compression else 0 + o['variables']['v8_enable_external_code_space'] = 1 if options.enable_pointer_compression else 0 o['variables']['v8_enable_31bit_smis_on_64bit_arch'] = 1 if options.enable_pointer_compression else 0 o['variables']['v8_enable_shared_ro_heap'] = 0 if options.enable_pointer_compression or options.disable_shared_ro_heap else 1 o['variables']['v8_enable_extensible_ro_snapshot'] = 0 @@ -1819,6 +1833,16 @@ def without_ssl_error(option): configure_library('openssl', o) +def configure_sqlite(o): + o['variables']['node_use_sqlite'] = b(not options.without_sqlite) + if options.without_sqlite: + def without_sqlite_error(option): + error(f'--without-sqlite is incompatible with {option}') + if options.shared_sqlite: + without_sqlite_error('--shared-sqlite') + return + + configure_library('sqlite', o, pkgname='sqlite3') def configure_static(o): if options.fully_static or options.partly_static: @@ -2262,8 +2286,8 @@ def make_bin_override(): configure_library('nghttp2', output, pkgname='libnghttp2') configure_library('nghttp3', output, pkgname='libnghttp3') configure_library('ngtcp2', output, pkgname='libngtcp2') -configure_library('sqlite', output, pkgname='sqlite3') -configure_library('uvwasi', output, pkgname='libuvwasi') +configure_sqlite(output); +configure_library('uvwasi', output) configure_library('zstd', output, pkgname='libzstd') configure_v8(output, configurations) configure_openssl(output) diff --git a/deps/cares/cares.gyp b/deps/cares/cares.gyp index c34ad7370ca45a..fee055c079f013 100644 --- a/deps/cares/cares.gyp +++ b/deps/cares/cares.gyp @@ -248,6 +248,10 @@ '-lnsl' ] } + }], + [ 'OS=="openharmony"', { + 'include_dirs': [ 'config/openharmony' ], + 'sources': [ 'config/openharmony/ares_config.h' ], }] ] } diff --git a/deps/cares/config/openharmony/ares_config.h b/deps/cares/config/openharmony/ares_config.h new file mode 100644 index 00000000000000..ec9f81d40e6a1e --- /dev/null +++ b/deps/cares/config/openharmony/ares_config.h @@ -0,0 +1,573 @@ +/* src/lib/ares_config.h. Generated from ares_config.h.in by configure. */ +/* src/lib/ares_config.h.in. Generated from configure.ac by autoheader. */ + +/* a suitable file/device to read random data from */ +#define CARES_RANDOM_FILE "/dev/urandom" + +/* Set to 1 if non-pubilc shared library symbols are hidden */ +#define CARES_SYMBOL_HIDING 1 + +/* Threading enabled */ +#define CARES_THREADS 1 + +/* the signed version of size_t */ +#define CARES_TYPEOF_ARES_SSIZE_T ssize_t + +/* Use resolver library to configure cares */ +/* #undef CARES_USE_LIBRESOLV */ + +/* if a /etc/inet dir is being used */ +/* #undef ETC_INET */ + +/* gethostname() arg2 type */ +#define GETHOSTNAME_TYPE_ARG2 size_t + +/* getnameinfo() arg1 type */ +#define GETNAMEINFO_TYPE_ARG1 struct sockaddr * + +/* getnameinfo() arg2 type */ +#define GETNAMEINFO_TYPE_ARG2 socklen_t + +/* getnameinfo() arg4 and 6 type */ +#define GETNAMEINFO_TYPE_ARG46 socklen_t + +/* getnameinfo() arg7 type */ +#define GETNAMEINFO_TYPE_ARG7 int + +/* number of arguments for getservbyname_r() */ +/* #undef GETSERVBYNAME_R_ARGS */ + +/* number of arguments for getservbyport_r() */ +#define GETSERVBYPORT_R_ARGS 6 + +/* Define to 1 if you have AF_INET6 */ +#define HAVE_AF_INET6 1 + +/* Define to 1 if you have `arc4random_buf` */ +/* #undef HAVE_ARC4RANDOM_BUF */ + +/* Define to 1 if you have the header file. */ +#define HAVE_ARPA_INET_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_ARPA_NAMESER_COMPAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_ARPA_NAMESER_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_ASSERT_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_AVAILABILITYMACROS_H */ + +/* Define to 1 if you have `clock_gettime` */ +#define HAVE_CLOCK_GETTIME 1 + +/* clock_gettime() with CLOCK_MONOTONIC support */ +#define HAVE_CLOCK_GETTIME_MONOTONIC 1 + +/* Define to 1 if you have `closesocket` */ +/* #undef HAVE_CLOSESOCKET */ + +/* Define to 1 if you have `CloseSocket` */ +/* #undef HAVE_CLOSESOCKET_CAMEL */ + +/* Define to 1 if you have `connect` */ +#define HAVE_CONNECT 1 + +/* Define to 1 if you have `ConvertInterfaceIndexToLuid` */ +/* #undef HAVE_CONVERTINTERFACEINDEXTOLUID */ + +/* Define to 1 if you have `ConvertInterfaceLuidToNameA` */ +/* #undef HAVE_CONVERTINTERFACELUIDTONAMEA */ + +/* define if the compiler supports basic C++14 syntax */ +#define HAVE_CXX14 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_DLFCN_H 1 + +/* Define to 1 if you have `epoll_{create1,ctl,wait}` */ +#define HAVE_EPOLL 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_ERRNO_H 1 + +/* Define to 1 if you have `fcntl` */ +#define HAVE_FCNTL 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_FCNTL_H 1 + +/* fcntl() with O_NONBLOCK support */ +#define HAVE_FCNTL_O_NONBLOCK 1 + +/* Define to 1 if you have `getenv` */ +#define HAVE_GETENV 1 + +/* Define to 1 if you have `gethostname` */ +#define HAVE_GETHOSTNAME 1 + +/* Define to 1 if you have `getifaddrs` */ +#define HAVE_GETIFADDRS 1 + +/* Define to 1 if you have `getnameinfo` */ +#define HAVE_GETNAMEINFO 1 + +/* Define to 1 if you have `getrandom` */ +#define HAVE_GETRANDOM 1 + +/* Define to 1 if you have `getservbyport_r` */ +/* #undef HAVE_GETSERVBYPORT_R 1 */ + +/* Define to 1 if you have `gettimeofday` */ +#define HAVE_GETTIMEOFDAY 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_IFADDRS_H 1 + +/* Define to 1 if you have `if_indextoname` */ +#define HAVE_IF_INDEXTONAME 1 + +/* Define to 1 if you have `if_nametoindex` */ +#define HAVE_IF_NAMETOINDEX 1 + +/* Define to 1 if you have `inet_net_pton` */ +#define HAVE_INET_NET_PTON 1 + +/* Define to 1 if you have `inet_ntop` */ +#define HAVE_INET_NTOP 1 + +/* Define to 1 if you have `inet_pton` */ +#define HAVE_INET_PTON 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have `ioctl` */ +#define HAVE_IOCTL 1 + +/* Define to 1 if you have `ioctlsocket` */ +/* #undef HAVE_IOCTLSOCKET */ + +/* Define to 1 if you have `IoctlSocket` */ +/* #undef HAVE_IOCTLSOCKET_CAMEL */ + +/* ioctlsocket() with FIONBIO support */ +/* #undef HAVE_IOCTLSOCKET_FIONBIO */ + +/* ioctl() with FIONBIO support */ +#define HAVE_IOCTL_FIONBIO 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_IPHLPAPI_H */ + +/* Define to 1 if you have `kqueue` */ +/* #undef HAVE_KQUEUE */ + +/* Define to 1 if you have the header file. */ +#define HAVE_LIMITS_H 1 + +/* Define to 1 if the compiler supports the 'long long' data type. */ +#define HAVE_LONGLONG 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_MALLOC_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_MINIX_CONFIG_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_MSWSOCK_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_NETDB_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_NETINET_IN_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_NETINET_TCP_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_NETIOAPI_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_NET_IF_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_NTDEF_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_NTSTATUS_H */ + +/* Define to 1 if you have PF_INET6 */ +#define HAVE_PF_INET6 1 + +/* Define to 1 if you have `pipe` */ +#define HAVE_PIPE 1 + +/* Define to 1 if you have `pipe2` */ +#define HAVE_PIPE2 1 + +/* Define to 1 if you have `poll` */ +#define HAVE_POLL 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_POLL_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_PTHREAD_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_PTHREAD_NP_H */ + +/* Have PTHREAD_PRIO_INHERIT. */ +#define HAVE_PTHREAD_PRIO_INHERIT 1 + +/* Define to 1 if you have `recv` */ +#define HAVE_RECV 1 + +/* Define to 1 if you have `recvfrom` */ +#define HAVE_RECVFROM 1 + +/* Define to 1 if you have `send` */ +#define HAVE_SEND 1 + +/* Define to 1 if you have `setsockopt` */ +#define HAVE_SETSOCKOPT 1 + +/* setsockopt() with SO_NONBLOCK support */ +/* #undef HAVE_SETSOCKOPT_SO_NONBLOCK */ + +/* Define to 1 if you have `socket` */ +#define HAVE_SOCKET 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SOCKET_H */ + +/* socklen_t */ +#define HAVE_SOCKLEN_T /**/ + +/* Define to 1 if you have `stat` */ +#define HAVE_STAT 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDBOOL_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDIO_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have `strcasecmp` */ +#define HAVE_STRCASECMP 1 + +/* Define to 1 if you have `strdup` */ +#define HAVE_STRDUP 1 + +/* Define to 1 if you have `stricmp` */ +/* #undef HAVE_STRICMP */ + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have `strncasecmp` */ +#define HAVE_STRNCASECMP 1 + +/* Define to 1 if you have `strncmpi` */ +/* #undef HAVE_STRNCMPI */ + +/* Define to 1 if you have `strnicmp` */ +/* #undef HAVE_STRNICMP */ + +/* Define to 1 if the system has the type `struct addrinfo'. */ +#define HAVE_STRUCT_ADDRINFO 1 + +/* Define to 1 if `ai_flags' is a member of `struct addrinfo'. */ +#define HAVE_STRUCT_ADDRINFO_AI_FLAGS 1 + +/* Define to 1 if the system has the type `struct in6_addr'. */ +#define HAVE_STRUCT_IN6_ADDR 1 + +/* Define to 1 if the system has the type `struct sockaddr_in6'. */ +#define HAVE_STRUCT_SOCKADDR_IN6 1 + +/* Define to 1 if `sin6_scope_id' is a member of `struct sockaddr_in6'. */ +#define HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID 1 + +/* Define to 1 if the system has the type `struct sockaddr_storage'. */ +#define HAVE_STRUCT_SOCKADDR_STORAGE 1 + +/* Define to 1 if the system has the type `struct timeval'. */ +#define HAVE_STRUCT_TIMEVAL 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_EPOLL_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_EVENT_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_FILIO_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_IOCTL_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_PARAM_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_RANDOM_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_SELECT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_SOCKET_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TIME_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_UIO_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_TIME_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* Whether user namespaces are available */ +#define HAVE_USER_NAMESPACE 1 + +/* Whether UTS namespaces are available */ +#define HAVE_UTS_NAMESPACE 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_WCHAR_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_WINDOWS_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_WINSOCK2_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_WINTERNL_H */ + +/* Define to 1 if you have `writev` */ +#define HAVE_WRITEV 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_WS2IPDEF_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_WS2TCPIP_H */ + +/* Define to 1 if you have `__system_property_get` */ +/* #undef HAVE___SYSTEM_PROPERTY_GET */ + +/* Define to the sub-directory where libtool stores uninstalled libraries. */ +#define LT_OBJDIR ".libs/" + +/* Name of package */ +#define PACKAGE "c-ares" + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "c-ares mailing list: http://lists.haxx.se/listinfo/c-ares" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "c-ares" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "c-ares 1.26.0" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "c-ares" + +/* Define to the home page for this package. */ +#define PACKAGE_URL "" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "1.26.0" + +/* Define to necessary symbol if this constant uses a non-standard name on + your system. */ +/* #undef PTHREAD_CREATE_JOINABLE */ + +/* recvfrom() arg5 qualifier */ +#define RECVFROM_QUAL_ARG5 + +/* recvfrom() arg1 type */ +#define RECVFROM_TYPE_ARG1 int + +/* recvfrom() arg2 type */ +#define RECVFROM_TYPE_ARG2 void * + +/* recvfrom() arg3 type */ +#define RECVFROM_TYPE_ARG3 size_t + +/* recvfrom() arg4 type */ +#define RECVFROM_TYPE_ARG4 int + +/* recvfrom() arg5 type */ +#define RECVFROM_TYPE_ARG5 struct sockaddr * + +/* recvfrom() return value */ +#define RECVFROM_TYPE_RETV ssize_t + +/* recv() arg1 type */ +#define RECV_TYPE_ARG1 int + +/* recv() arg2 type */ +#define RECV_TYPE_ARG2 void * + +/* recv() arg3 type */ +#define RECV_TYPE_ARG3 size_t + +/* recv() arg4 type */ +#define RECV_TYPE_ARG4 int + +/* recv() return value */ +#define RECV_TYPE_RETV ssize_t + +/* send() arg2 qualifier */ +#define SEND_QUAL_ARG2 + +/* send() arg1 type */ +#define SEND_TYPE_ARG1 int + +/* send() arg2 type */ +#define SEND_TYPE_ARG2 void * + +/* send() arg3 type */ +#define SEND_TYPE_ARG3 size_t + +/* send() arg4 type */ +#define SEND_TYPE_ARG4 int + +/* send() return value */ +#define SEND_TYPE_RETV ssize_t + +/* Define to 1 if all of the C90 standard headers exist (not just the ones + required in a freestanding environment). This macro is provided for + backward compatibility; new code need not use it. */ +#define STDC_HEADERS 1 + +/* Enable extensions on AIX 3, Interix. */ +#ifndef _ALL_SOURCE +# define _ALL_SOURCE 1 +#endif +/* Enable general extensions on macOS. */ +#ifndef _DARWIN_C_SOURCE +# define _DARWIN_C_SOURCE 1 +#endif +/* Enable general extensions on Solaris. */ +#ifndef __EXTENSIONS__ +# define __EXTENSIONS__ 1 +#endif +/* Enable GNU extensions on systems that have them. */ +#ifndef _GNU_SOURCE +# define _GNU_SOURCE 1 +#endif +/* Enable X/Open compliant socket functions that do not require linking + with -lxnet on HP-UX 11.11. */ +#ifndef _HPUX_ALT_XOPEN_SOCKET_API +# define _HPUX_ALT_XOPEN_SOCKET_API 1 +#endif +/* Identify the host operating system as Minix. + This macro does not affect the system headers' behavior. + A future release of Autoconf may stop defining this macro. */ +#ifndef _MINIX +/* # undef _MINIX */ +#endif +/* Enable general extensions on NetBSD. + Enable NetBSD compatibility extensions on Minix. */ +#ifndef _NETBSD_SOURCE +# define _NETBSD_SOURCE 1 +#endif +/* Enable OpenBSD compatibility extensions on NetBSD. + Oddly enough, this does nothing on OpenBSD. */ +#ifndef _OPENBSD_SOURCE +# define _OPENBSD_SOURCE 1 +#endif +/* Define to 1 if needed for POSIX-compatible behavior. */ +#ifndef _POSIX_SOURCE +/* # undef _POSIX_SOURCE */ +#endif +/* Define to 2 if needed for POSIX-compatible behavior. */ +#ifndef _POSIX_1_SOURCE +/* # undef _POSIX_1_SOURCE */ +#endif +/* Enable POSIX-compatible threading on Solaris. */ +#ifndef _POSIX_PTHREAD_SEMANTICS +# define _POSIX_PTHREAD_SEMANTICS 1 +#endif +/* Enable extensions specified by ISO/IEC TS 18661-5:2014. */ +#ifndef __STDC_WANT_IEC_60559_ATTRIBS_EXT__ +# define __STDC_WANT_IEC_60559_ATTRIBS_EXT__ 1 +#endif +/* Enable extensions specified by ISO/IEC TS 18661-1:2014. */ +#ifndef __STDC_WANT_IEC_60559_BFP_EXT__ +# define __STDC_WANT_IEC_60559_BFP_EXT__ 1 +#endif +/* Enable extensions specified by ISO/IEC TS 18661-2:2015. */ +#ifndef __STDC_WANT_IEC_60559_DFP_EXT__ +# define __STDC_WANT_IEC_60559_DFP_EXT__ 1 +#endif +/* Enable extensions specified by ISO/IEC TS 18661-4:2015. */ +#ifndef __STDC_WANT_IEC_60559_FUNCS_EXT__ +# define __STDC_WANT_IEC_60559_FUNCS_EXT__ 1 +#endif +/* Enable extensions specified by ISO/IEC TS 18661-3:2015. */ +#ifndef __STDC_WANT_IEC_60559_TYPES_EXT__ +# define __STDC_WANT_IEC_60559_TYPES_EXT__ 1 +#endif +/* Enable extensions specified by ISO/IEC TR 24731-2:2010. */ +#ifndef __STDC_WANT_LIB_EXT2__ +# define __STDC_WANT_LIB_EXT2__ 1 +#endif +/* Enable extensions specified by ISO/IEC 24747:2009. */ +#ifndef __STDC_WANT_MATH_SPEC_FUNCS__ +# define __STDC_WANT_MATH_SPEC_FUNCS__ 1 +#endif +/* Enable extensions on HP NonStop. */ +#ifndef _TANDEM_SOURCE +# define _TANDEM_SOURCE 1 +#endif +/* Enable X/Open extensions. Define to 500 only if necessary + to make mbstate_t available. */ +#ifndef _XOPEN_SOURCE +/* # undef _XOPEN_SOURCE */ +#endif + + +/* Version number of package */ +#define VERSION "1.26.0" + +/* Number of bits in a file offset, on hosts where this is settable. */ +/* #undef _FILE_OFFSET_BITS */ + +/* Define for large files, on AIX-style hosts. */ +/* #undef _LARGE_FILES */ + +/* Define to `unsigned int' if does not define. */ +/* #undef size_t */ diff --git a/deps/corepack/CHANGELOG.md b/deps/corepack/CHANGELOG.md index ad0bba51c6b83f..e4f0b185a73616 100644 --- a/deps/corepack/CHANGELOG.md +++ b/deps/corepack/CHANGELOG.md @@ -1,5 +1,18 @@ # Changelog +## [0.33.0](https://github.com/nodejs/corepack/compare/v0.32.0...v0.33.0) (2025-06-02) + + +### Features + +* Adds guard to avoid stepping on Yarn's feet ([#714](https://github.com/nodejs/corepack/issues/714)) ([5fc3691](https://github.com/nodejs/corepack/commit/5fc3691354eb5bdeca17a9495b234584353f0151)) +* update package manager versions ([#671](https://github.com/nodejs/corepack/issues/671)) ([b45b3a3](https://github.com/nodejs/corepack/commit/b45b3a3244bacfbaf65188ae8c04209a1e98307d)) + + +### Bug Fixes + +* debug text typo ([#698](https://github.com/nodejs/corepack/issues/698)) ([0b94797](https://github.com/nodejs/corepack/commit/0b94797f96e30e46e466873fe7d437d0471cd92c)) + ## [0.32.0](https://github.com/nodejs/corepack/compare/v0.31.0...v0.32.0) (2025-02-28) diff --git a/deps/corepack/README.md b/deps/corepack/README.md index 67d396d5ca9642..079746ee796366 100644 --- a/deps/corepack/README.md +++ b/deps/corepack/README.md @@ -286,8 +286,8 @@ same major line. Should you need to upgrade to a new major, use an explicit package manager, and to not update the Last Known Good version when it downloads a new version of the same major line. -- `COREPACK_ENABLE_AUTO_PIN` can be set to `0` to prevent Corepack from - updating the `packageManager` field when it detects that the local package +- `COREPACK_ENABLE_AUTO_PIN` can be set to `1` to instruct Corepack to + update the `packageManager` field when it detects that the local package doesn't list it. In general we recommend to always list a `packageManager` field (which you can easily set through `corepack use [name]@[version]`), as it ensures that your project installs are always deterministic. diff --git a/deps/corepack/dist/lib/corepack.cjs b/deps/corepack/dist/lib/corepack.cjs index 7a098cbe250aab..c6854077d0fa6b 100644 --- a/deps/corepack/dist/lib/corepack.cjs +++ b/deps/corepack/dist/lib/corepack.cjs @@ -21683,7 +21683,7 @@ function String2(descriptor, ...args) { } // package.json -var version = "0.32.0"; +var version = "0.33.0"; // sources/Engine.ts var import_fs9 = __toESM(require("fs")); @@ -21697,7 +21697,7 @@ var import_valid4 = __toESM(require_valid2()); var config_default = { definitions: { npm: { - default: "11.1.0+sha1.dba08f7d0f5301ebedaf968b4f74b2282f97a750", + default: "11.4.1+sha1.80350af543069991de20657ebcd07d9624cfad06", fetchLatestFrom: { type: "npm", package: "npm" @@ -21734,7 +21734,7 @@ var config_default = { } }, pnpm: { - default: "10.5.2+sha1.ca68c0441df195b7e2992f1d1cb12fb731f82d78", + default: "10.11.0+sha1.4048eeefd564ff1ab248fac3e2854d38245fe2f1", fetchLatestFrom: { type: "npm", package: "pnpm" @@ -21798,7 +21798,7 @@ var config_default = { package: "yarn" }, transparent: { - default: "4.6.0+sha224.acd0786f07ffc6c933940eb65fc1d627131ddf5455bddcc295dc90fd", + default: "4.9.1+sha224.4285002185abb91fe2b781f27fd1e078086c37a7b095f6ea4ee25971", commands: [ [ "yarn", @@ -22105,6 +22105,10 @@ async function getProxyAgent(input) { } // sources/corepackUtils.ts +var YARN_SWITCH_REGEX = /[/\\]switch[/\\]bin[/\\]/; +function isYarnSwitchPath(p) { + return YARN_SWITCH_REGEX.test(p); +} function getRegistryFromPackageManagerSpec(spec) { return process.env.COREPACK_NPM_REGISTRY ? spec.npmRegistry ?? spec.registry : spec.registry; } @@ -22896,7 +22900,7 @@ var Engine = class { case `NoSpec`: { if (typeof locator.reference === `function`) fallbackDescriptor.range = await locator.reference(); - if (import_process3.default.env.COREPACK_ENABLE_AUTO_PIN !== `0`) { + if (import_process3.default.env.COREPACK_ENABLE_AUTO_PIN === `1`) { const resolved = await this.resolveDescriptor(fallbackDescriptor, { allowTags: true }); if (resolved === null) throw new UsageError(`Failed to successfully resolve '${fallbackDescriptor.range}' to a valid ${fallbackDescriptor.name} release`); @@ -22906,7 +22910,7 @@ var Engine = class { console.error(); await setLocalPackageManager(import_path9.default.dirname(result.target), installSpec); } - log(`Falling back to ${fallbackDescriptor.name}@${fallbackDescriptor.range} in the absence of "packageManage" field in ${result.target}`); + log(`Falling back to ${fallbackDescriptor.name}@${fallbackDescriptor.range} in the absence of "packageManager" field in ${result.target}`); return fallbackDescriptor; } case `Found`: { @@ -23070,6 +23074,10 @@ var DisableCommand = class extends Command { async removePosixLink(installDirectory, binName) { const file = import_path10.default.join(installDirectory, binName); try { + if (binName.includes(`yarn`) && isYarnSwitchPath(await import_fs11.default.promises.realpath(file))) { + console.warn(`${binName} is already installed in ${file} and points to a Yarn Switch install - skipping`); + return; + } await import_fs11.default.promises.unlink(file); } catch (err) { if (err.code !== `ENOENT`) { @@ -23147,6 +23155,10 @@ var EnableCommand = class extends Command { const symlink = import_path11.default.relative(installDirectory, import_path11.default.join(distFolder, `${binName}.js`)); if (import_fs12.default.existsSync(file)) { const currentSymlink = await import_fs12.default.promises.readlink(file); + if (binName.includes(`yarn`) && isYarnSwitchPath(await import_fs12.default.promises.realpath(file))) { + console.warn(`${binName} is already installed in ${file} and points to a Yarn Switch install - skipping`); + return; + } if (currentSymlink !== symlink) { await import_fs12.default.promises.unlink(file); } else { diff --git a/deps/corepack/package.json b/deps/corepack/package.json index 75f5725328a605..7bf3d9e6604a50 100644 --- a/deps/corepack/package.json +++ b/deps/corepack/package.json @@ -1,6 +1,6 @@ { "name": "corepack", - "version": "0.32.0", + "version": "0.33.0", "homepage": "https://github.com/nodejs/corepack#readme", "bugs": { "url": "https://github.com/nodejs/corepack/issues" @@ -16,21 +16,21 @@ "./package.json": "./package.json" }, "license": "MIT", - "packageManager": "yarn@4.6.0+sha512.5383cc12567a95f1d668fbe762dfe0075c595b4bfff433be478dbbe24e05251a8e8c3eb992a986667c1d53b6c3a9c85b8398c35a960587fbd9fa3a0915406728", + "packageManager": "yarn@4.9.0+sha224.dce6c5df199861784bd9b0eecb2a228df97e3f18a02b1bb75ff98383", "devDependencies": { "@types/debug": "^4.1.5", "@types/node": "^20.4.6", "@types/proxy-from-env": "^1", "@types/semver": "^7.1.0", "@types/which": "^3.0.0", - "@yarnpkg/eslint-config": "^2.0.0", + "@yarnpkg/eslint-config": "^3.0.0", "@yarnpkg/fslib": "^3.0.0-rc.48", "@zkochan/cmd-shim": "^6.0.0", "better-sqlite3": "^11.7.2", "clipanion": "patch:clipanion@npm%3A3.2.1#~/.yarn/patches/clipanion-npm-3.2.1-fc9187f56c.patch", "debug": "^4.1.1", "esbuild": "^0.25.0", - "eslint": "^8.57.0", + "eslint": "^9.22.0", "proxy-from-env": "^1.1.0", "semver": "^7.6.3", "supports-color": "^10.0.0", diff --git a/deps/googletest/include/gtest/gtest-printers.h b/deps/googletest/include/gtest/gtest-printers.h index 198a7693493a33..048c32db2e7c2e 100644 --- a/deps/googletest/include/gtest/gtest-printers.h +++ b/deps/googletest/include/gtest/gtest-printers.h @@ -104,15 +104,19 @@ #ifndef GOOGLETEST_INCLUDE_GTEST_GTEST_PRINTERS_H_ #define GOOGLETEST_INCLUDE_GTEST_GTEST_PRINTERS_H_ +#include #include #include +#include #include // NOLINT #include #include +#include #include #include #include #include +#include #include #ifdef GTEST_HAS_ABSL @@ -245,8 +249,8 @@ struct StreamPrinter { // ADL (possibly involving implicit conversions). // (Use SFINAE via return type, because it seems GCC < 12 doesn't handle name // lookup properly when we do it in the template parameter list.) - static auto PrintValue(const T& value, - ::std::ostream* os) -> decltype((void)(*os << value)) { + static auto PrintValue(const T& value, ::std::ostream* os) + -> decltype((void)(*os << value)) { // Call streaming operator found by ADL, possibly with implicit conversions // of the arguments. *os << value; @@ -521,11 +525,15 @@ GTEST_API_ void PrintTo(wchar_t wc, ::std::ostream* os); GTEST_API_ void PrintTo(char32_t c, ::std::ostream* os); inline void PrintTo(char16_t c, ::std::ostream* os) { - PrintTo(ImplicitCast_(c), os); + // TODO(b/418738869): Incorrect for values not representing valid codepoints. + // Also see https://github.com/google/googletest/issues/4762. + PrintTo(static_cast(c), os); } #ifdef __cpp_lib_char8_t inline void PrintTo(char8_t c, ::std::ostream* os) { - PrintTo(ImplicitCast_(c), os); + // TODO(b/418738869): Incorrect for values not representing valid codepoints. + // Also see https://github.com/google/googletest/issues/4762. + PrintTo(static_cast(c), os); } #endif @@ -695,44 +703,63 @@ void PrintRawArrayTo(const T a[], size_t count, ::std::ostream* os) { } } -// Overloads for ::std::string. -GTEST_API_ void PrintStringTo(const ::std::string& s, ::std::ostream* os); +// Overloads for ::std::string and ::std::string_view +GTEST_API_ void PrintStringTo(::std::string_view s, ::std::ostream* os); inline void PrintTo(const ::std::string& s, ::std::ostream* os) { PrintStringTo(s, os); } +inline void PrintTo(::std::string_view s, ::std::ostream* os) { + PrintStringTo(s, os); +} -// Overloads for ::std::u8string +// Overloads for ::std::u8string and ::std::u8string_view #ifdef __cpp_lib_char8_t -GTEST_API_ void PrintU8StringTo(const ::std::u8string& s, ::std::ostream* os); +GTEST_API_ void PrintU8StringTo(::std::u8string_view s, ::std::ostream* os); inline void PrintTo(const ::std::u8string& s, ::std::ostream* os) { PrintU8StringTo(s, os); } +inline void PrintTo(::std::u8string_view s, ::std::ostream* os) { + PrintU8StringTo(s, os); +} #endif -// Overloads for ::std::u16string -GTEST_API_ void PrintU16StringTo(const ::std::u16string& s, ::std::ostream* os); +// Overloads for ::std::u16string and ::std::u16string_view +GTEST_API_ void PrintU16StringTo(::std::u16string_view s, ::std::ostream* os); inline void PrintTo(const ::std::u16string& s, ::std::ostream* os) { PrintU16StringTo(s, os); } +inline void PrintTo(::std::u16string_view s, ::std::ostream* os) { + PrintU16StringTo(s, os); +} -// Overloads for ::std::u32string -GTEST_API_ void PrintU32StringTo(const ::std::u32string& s, ::std::ostream* os); +// Overloads for ::std::u32string and ::std::u32string_view +GTEST_API_ void PrintU32StringTo(::std::u32string_view s, ::std::ostream* os); inline void PrintTo(const ::std::u32string& s, ::std::ostream* os) { PrintU32StringTo(s, os); } +inline void PrintTo(::std::u32string_view s, ::std::ostream* os) { + PrintU32StringTo(s, os); +} -// Overloads for ::std::wstring. +// Overloads for ::std::wstring and ::std::wstring_view #if GTEST_HAS_STD_WSTRING -GTEST_API_ void PrintWideStringTo(const ::std::wstring& s, ::std::ostream* os); +GTEST_API_ void PrintWideStringTo(::std::wstring_view s, ::std::ostream* os); inline void PrintTo(const ::std::wstring& s, ::std::ostream* os) { PrintWideStringTo(s, os); } +inline void PrintTo(::std::wstring_view s, ::std::ostream* os) { + PrintWideStringTo(s, os); +} #endif // GTEST_HAS_STD_WSTRING #if GTEST_INTERNAL_HAS_STRING_VIEW -// Overload for internal::StringView. +// Overload for internal::StringView. Needed for build configurations where +// internal::StringView is an alias for absl::string_view, but absl::string_view +// is a distinct type from std::string_view. +template , int> = 0> inline void PrintTo(internal::StringView sp, ::std::ostream* os) { - PrintTo(::std::string(sp), os); + PrintStringTo(sp, os); } #endif // GTEST_INTERNAL_HAS_STRING_VIEW @@ -890,14 +917,11 @@ class UniversalPrinter { template class UniversalPrinter : public UniversalPrinter {}; -#if GTEST_INTERNAL_HAS_ANY - -// Printer for std::any / absl::any - +// Printer for std::any template <> -class UniversalPrinter { +class UniversalPrinter { public: - static void Print(const Any& value, ::std::ostream* os) { + static void Print(const std::any& value, ::std::ostream* os) { if (value.has_value()) { *os << "value of type " << GetTypeName(value); } else { @@ -906,7 +930,7 @@ class UniversalPrinter { } private: - static std::string GetTypeName(const Any& value) { + static std::string GetTypeName(const std::any& value) { #if GTEST_HAS_RTTI return internal::GetTypeName(value.type()); #else @@ -916,16 +940,11 @@ class UniversalPrinter { } }; -#endif // GTEST_INTERNAL_HAS_ANY - -#if GTEST_INTERNAL_HAS_OPTIONAL - -// Printer for std::optional / absl::optional - +// Printer for std::optional template -class UniversalPrinter> { +class UniversalPrinter> { public: - static void Print(const Optional& value, ::std::ostream* os) { + static void Print(const std::optional& value, ::std::ostream* os) { *os << '('; if (!value) { *os << "nullopt"; @@ -937,29 +956,18 @@ class UniversalPrinter> { }; template <> -class UniversalPrinter { +class UniversalPrinter { public: - static void Print(decltype(Nullopt()), ::std::ostream* os) { - *os << "(nullopt)"; - } + static void Print(std::nullopt_t, ::std::ostream* os) { *os << "(nullopt)"; } }; -#endif // GTEST_INTERNAL_HAS_OPTIONAL - -#if GTEST_INTERNAL_HAS_VARIANT - -// Printer for std::variant / absl::variant - +// Printer for std::variant template -class UniversalPrinter> { +class UniversalPrinter> { public: - static void Print(const Variant& value, ::std::ostream* os) { + static void Print(const std::variant& value, ::std::ostream* os) { *os << '('; -#ifdef GTEST_HAS_ABSL - absl::visit(Visitor{os, value.index()}, value); -#else std::visit(Visitor{os, value.index()}, value); -#endif // GTEST_HAS_ABSL *os << ')'; } @@ -976,8 +984,6 @@ class UniversalPrinter> { }; }; -#endif // GTEST_INTERNAL_HAS_VARIANT - // UniversalPrintArray(begin, len, os) prints an array of 'len' // elements, starting at address 'begin'. template diff --git a/deps/googletest/include/gtest/gtest.h b/deps/googletest/include/gtest/gtest.h index 7be0caaf515cf8..cbe680c1adb266 100644 --- a/deps/googletest/include/gtest/gtest.h +++ b/deps/googletest/include/gtest/gtest.h @@ -1693,7 +1693,7 @@ class WithParamInterface { // The current parameter value. Is also available in the test fixture's // constructor. - static const ParamType& GetParam() { + [[nodiscard]] static const ParamType& GetParam() { GTEST_CHECK_(parameter_ != nullptr) << "GetParam() can only be called inside a value-parameterized test " << "-- did you intend to write TEST_P instead of TEST_F?"; diff --git a/deps/googletest/include/gtest/internal/gtest-internal.h b/deps/googletest/include/gtest/internal/gtest-internal.h index dcab397e92320a..808d89be91439a 100644 --- a/deps/googletest/include/gtest/internal/gtest-internal.h +++ b/deps/googletest/include/gtest/internal/gtest-internal.h @@ -290,17 +290,17 @@ class FloatingPoint { // around may change its bits, although the new value is guaranteed // to be also a NAN. Therefore, don't expect this constructor to // preserve the bits in x when x is a NAN. - explicit FloatingPoint(const RawType& x) { u_.value_ = x; } + explicit FloatingPoint(RawType x) { memcpy(&bits_, &x, sizeof(x)); } // Static methods // Reinterprets a bit pattern as a floating-point number. // // This function is needed to test the AlmostEquals() method. - static RawType ReinterpretBits(const Bits bits) { - FloatingPoint fp(0); - fp.u_.bits_ = bits; - return fp.u_.value_; + static RawType ReinterpretBits(Bits bits) { + RawType fp; + memcpy(&fp, &bits, sizeof(fp)); + return fp; } // Returns the floating-point number that represent positive infinity. @@ -309,16 +309,16 @@ class FloatingPoint { // Non-static methods // Returns the bits that represents this number. - const Bits& bits() const { return u_.bits_; } + const Bits& bits() const { return bits_; } // Returns the exponent bits of this number. - Bits exponent_bits() const { return kExponentBitMask & u_.bits_; } + Bits exponent_bits() const { return kExponentBitMask & bits_; } // Returns the fraction bits of this number. - Bits fraction_bits() const { return kFractionBitMask & u_.bits_; } + Bits fraction_bits() const { return kFractionBitMask & bits_; } // Returns the sign bit of this number. - Bits sign_bit() const { return kSignBitMask & u_.bits_; } + Bits sign_bit() const { return kSignBitMask & bits_; } // Returns true if and only if this is NAN (not a number). bool is_nan() const { @@ -332,23 +332,16 @@ class FloatingPoint { // // - returns false if either number is (or both are) NAN. // - treats really large numbers as almost equal to infinity. - // - thinks +0.0 and -0.0 are 0 DLP's apart. + // - thinks +0.0 and -0.0 are 0 ULP's apart. bool AlmostEquals(const FloatingPoint& rhs) const { // The IEEE standard says that any comparison operation involving // a NAN must return false. if (is_nan() || rhs.is_nan()) return false; - return DistanceBetweenSignAndMagnitudeNumbers(u_.bits_, rhs.u_.bits_) <= - kMaxUlps; + return DistanceBetweenSignAndMagnitudeNumbers(bits_, rhs.bits_) <= kMaxUlps; } private: - // The data type used to store the actual floating-point number. - union FloatingPointUnion { - RawType value_; // The raw floating-point number. - Bits bits_; // The bits that represent the number. - }; - // Converts an integer from the sign-and-magnitude representation to // the biased representation. More precisely, let N be 2 to the // power of (kBitCount - 1), an integer x is represented by the @@ -364,7 +357,7 @@ class FloatingPoint { // // Read https://en.wikipedia.org/wiki/Signed_number_representations // for more details on signed number representations. - static Bits SignAndMagnitudeToBiased(const Bits& sam) { + static Bits SignAndMagnitudeToBiased(Bits sam) { if (kSignBitMask & sam) { // sam represents a negative number. return ~sam + 1; @@ -376,14 +369,13 @@ class FloatingPoint { // Given two numbers in the sign-and-magnitude representation, // returns the distance between them as an unsigned number. - static Bits DistanceBetweenSignAndMagnitudeNumbers(const Bits& sam1, - const Bits& sam2) { + static Bits DistanceBetweenSignAndMagnitudeNumbers(Bits sam1, Bits sam2) { const Bits biased1 = SignAndMagnitudeToBiased(sam1); const Bits biased2 = SignAndMagnitudeToBiased(sam2); return (biased1 >= biased2) ? (biased1 - biased2) : (biased2 - biased1); } - FloatingPointUnion u_; + Bits bits_; // The bits that represent the number. }; // Typedefs the instances of the FloatingPoint template class that we diff --git a/deps/googletest/include/gtest/internal/gtest-port.h b/deps/googletest/include/gtest/internal/gtest-port.h index 4cfc16c03e9d38..06a5a8e6f31935 100644 --- a/deps/googletest/include/gtest/internal/gtest-port.h +++ b/deps/googletest/include/gtest/internal/gtest-port.h @@ -198,21 +198,8 @@ // suppressed (constant conditional). // GTEST_INTENTIONAL_CONST_COND_POP_ - finish code section where MSVC C4127 // is suppressed. -// GTEST_INTERNAL_HAS_ANY - for enabling UniversalPrinter or -// UniversalPrinter specializations. -// Always defined to 0 or 1. -// GTEST_INTERNAL_HAS_OPTIONAL - for enabling UniversalPrinter -// or -// UniversalPrinter -// specializations. Always defined to 0 or 1. // GTEST_INTERNAL_HAS_STD_SPAN - for enabling UniversalPrinter // specializations. Always defined to 0 or 1 -// GTEST_INTERNAL_HAS_STRING_VIEW - for enabling Matcher or -// Matcher -// specializations. Always defined to 0 or 1. -// GTEST_INTERNAL_HAS_VARIANT - for enabling UniversalPrinter or -// UniversalPrinter -// specializations. Always defined to 0 or 1. // GTEST_USE_OWN_FLAGFILE_FLAG_ - Always defined to 0 or 1. // GTEST_HAS_CXXABI_H_ - Always defined to 0 or 1. // GTEST_CAN_STREAM_RESULTS_ - Always defined to 0 or 1. @@ -282,10 +269,14 @@ // Detect C++ feature test macros as gracefully as possible. // MSVC >= 19.15, Clang >= 3.4.1, and GCC >= 4.1.2 support feature test macros. -#if GTEST_INTERNAL_CPLUSPLUS_LANG >= 202002L && \ - (!defined(__has_include) || GTEST_INTERNAL_HAS_INCLUDE()) -#include // C++20 and later -#elif (!defined(__has_include) || GTEST_INTERNAL_HAS_INCLUDE()) +// +// GCC15 warns that is deprecated in C++17 and suggests using +// instead, even though is not available in C++17 mode prior +// to GCC9. +#if GTEST_INTERNAL_CPLUSPLUS_LANG >= 202002L || \ + GTEST_INTERNAL_HAS_INCLUDE() +#include // C++20 or support. +#else #include // Pre-C++20 #endif @@ -2331,73 +2322,6 @@ const char* StringFromGTestEnv(const char* flag, const char* default_val); } // namespace internal } // namespace testing -#ifdef GTEST_HAS_ABSL -// Always use absl::any for UniversalPrinter<> specializations if googletest -// is built with absl support. -#define GTEST_INTERNAL_HAS_ANY 1 -#include "absl/types/any.h" -namespace testing { -namespace internal { -using Any = ::absl::any; -} // namespace internal -} // namespace testing -#else -#if defined(__cpp_lib_any) || (GTEST_INTERNAL_HAS_INCLUDE() && \ - GTEST_INTERNAL_CPLUSPLUS_LANG >= 201703L && \ - (!defined(_MSC_VER) || GTEST_HAS_RTTI)) -// Otherwise for C++17 and higher use std::any for UniversalPrinter<> -// specializations. -#define GTEST_INTERNAL_HAS_ANY 1 -#include -namespace testing { -namespace internal { -using Any = ::std::any; -} // namespace internal -} // namespace testing -// The case where absl is configured NOT to alias std::any is not -// supported. -#endif // __cpp_lib_any -#endif // GTEST_HAS_ABSL - -#ifndef GTEST_INTERNAL_HAS_ANY -#define GTEST_INTERNAL_HAS_ANY 0 -#endif - -#ifdef GTEST_HAS_ABSL -// Always use absl::optional for UniversalPrinter<> specializations if -// googletest is built with absl support. -#define GTEST_INTERNAL_HAS_OPTIONAL 1 -#include "absl/types/optional.h" -namespace testing { -namespace internal { -template -using Optional = ::absl::optional; -inline ::absl::nullopt_t Nullopt() { return ::absl::nullopt; } -} // namespace internal -} // namespace testing -#else -#if defined(__cpp_lib_optional) || (GTEST_INTERNAL_HAS_INCLUDE() && \ - GTEST_INTERNAL_CPLUSPLUS_LANG >= 201703L) -// Otherwise for C++17 and higher use std::optional for UniversalPrinter<> -// specializations. -#define GTEST_INTERNAL_HAS_OPTIONAL 1 -#include -namespace testing { -namespace internal { -template -using Optional = ::std::optional; -inline ::std::nullopt_t Nullopt() { return ::std::nullopt; } -} // namespace internal -} // namespace testing -// The case where absl is configured NOT to alias std::optional is not -// supported. -#endif // __cpp_lib_optional -#endif // GTEST_HAS_ABSL - -#ifndef GTEST_INTERNAL_HAS_OPTIONAL -#define GTEST_INTERNAL_HAS_OPTIONAL 0 -#endif - #if defined(__cpp_lib_span) || (GTEST_INTERNAL_HAS_INCLUDE() && \ GTEST_INTERNAL_CPLUSPLUS_LANG >= 202002L) #define GTEST_INTERNAL_HAS_STD_SPAN 1 @@ -2439,38 +2363,6 @@ using StringView = ::std::string_view; #define GTEST_INTERNAL_HAS_STRING_VIEW 0 #endif -#ifdef GTEST_HAS_ABSL -// Always use absl::variant for UniversalPrinter<> specializations if googletest -// is built with absl support. -#define GTEST_INTERNAL_HAS_VARIANT 1 -#include "absl/types/variant.h" -namespace testing { -namespace internal { -template -using Variant = ::absl::variant; -} // namespace internal -} // namespace testing -#else -#if defined(__cpp_lib_variant) || (GTEST_INTERNAL_HAS_INCLUDE() && \ - GTEST_INTERNAL_CPLUSPLUS_LANG >= 201703L) -// Otherwise for C++17 and higher use std::variant for UniversalPrinter<> -// specializations. -#define GTEST_INTERNAL_HAS_VARIANT 1 -#include -namespace testing { -namespace internal { -template -using Variant = ::std::variant; -} // namespace internal -} // namespace testing -// The case where absl is configured NOT to alias std::variant is not supported. -#endif // __cpp_lib_variant -#endif // GTEST_HAS_ABSL - -#ifndef GTEST_INTERNAL_HAS_VARIANT -#define GTEST_INTERNAL_HAS_VARIANT 0 -#endif - #if (defined(__cpp_lib_three_way_comparison) || \ (GTEST_INTERNAL_HAS_INCLUDE() && \ GTEST_INTERNAL_CPLUSPLUS_LANG >= 201907L)) diff --git a/deps/googletest/src/gtest-printers.cc b/deps/googletest/src/gtest-printers.cc index e3acecba8e4dec..f65573077861b4 100644 --- a/deps/googletest/src/gtest-printers.cc +++ b/deps/googletest/src/gtest-printers.cc @@ -50,7 +50,7 @@ #include #include #include // NOLINT -#include +#include #include #include "gtest/internal/gtest-port.h" @@ -333,14 +333,14 @@ void PrintTo(__int128_t v, ::std::ostream* os) { // Prints the given array of characters to the ostream. CharType must be either // char, char8_t, char16_t, char32_t, or wchar_t. -// The array starts at begin, the length is len, it may include '\0' characters -// and may not be NUL-terminated. +// The array starts at begin (which may be nullptr) and contains len characters. +// The array may include '\0' characters and may not be NUL-terminated. template GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_ GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_ GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_ static CharFormat PrintCharsAsStringTo(const CharType* begin, size_t len, ostream* os) { - const char* const quote_prefix = GetCharWidthPrefix(*begin); + const char* const quote_prefix = GetCharWidthPrefix(CharType()); *os << quote_prefix << "\""; bool is_previous_hex = false; CharFormat print_format = kAsIs; @@ -516,13 +516,13 @@ bool IsValidUTF8(const char* str, size_t length) { void ConditionalPrintAsText(const char* str, size_t length, ostream* os) { if (!ContainsUnprintableControlCodes(str, length) && IsValidUTF8(str, length)) { - *os << "\n As Text: \"" << str << "\""; + *os << "\n As Text: \"" << ::std::string_view(str, length) << "\""; } } } // anonymous namespace -void PrintStringTo(const ::std::string& s, ostream* os) { +void PrintStringTo(::std::string_view s, ostream* os) { if (PrintCharsAsStringTo(s.data(), s.size(), os) == kHexEscape) { if (GTEST_FLAG_GET(print_utf8)) { ConditionalPrintAsText(s.data(), s.size(), os); @@ -531,21 +531,21 @@ void PrintStringTo(const ::std::string& s, ostream* os) { } #ifdef __cpp_lib_char8_t -void PrintU8StringTo(const ::std::u8string& s, ostream* os) { +void PrintU8StringTo(::std::u8string_view s, ostream* os) { PrintCharsAsStringTo(s.data(), s.size(), os); } #endif -void PrintU16StringTo(const ::std::u16string& s, ostream* os) { +void PrintU16StringTo(::std::u16string_view s, ostream* os) { PrintCharsAsStringTo(s.data(), s.size(), os); } -void PrintU32StringTo(const ::std::u32string& s, ostream* os) { +void PrintU32StringTo(::std::u32string_view s, ostream* os) { PrintCharsAsStringTo(s.data(), s.size(), os); } #if GTEST_HAS_STD_WSTRING -void PrintWideStringTo(const ::std::wstring& s, ostream* os) { +void PrintWideStringTo(::std::wstring_view s, ostream* os) { PrintCharsAsStringTo(s.data(), s.size(), os); } #endif // GTEST_HAS_STD_WSTRING diff --git a/deps/googletest/src/gtest.cc b/deps/googletest/src/gtest.cc index 09af15179f1f9f..6be9300e09d1d4 100644 --- a/deps/googletest/src/gtest.cc +++ b/deps/googletest/src/gtest.cc @@ -1488,17 +1488,17 @@ class Hunk { // Print a unified diff header for one hunk. // The format is // "@@ -, +, @@" - // where the left/right parts are omitted if unnecessary. + // where the left/right lengths are omitted if unnecessary. void PrintHeader(std::ostream* ss) const { - *ss << "@@ "; - if (removes_) { - *ss << "-" << left_start_ << "," << (removes_ + common_); + size_t left_length = removes_ + common_; + size_t right_length = adds_ + common_; + *ss << "@@ " << "-" << left_start_; + if (left_length != 1) { + *ss << "," << left_length; } - if (removes_ && adds_) { - *ss << " "; - } - if (adds_) { - *ss << "+" << right_start_ << "," << (adds_ + common_); + *ss << " " << "+" << right_start_; + if (right_length != 1) { + *ss << "," << right_length; } *ss << " @@\n"; } diff --git a/deps/llhttp/CMakeLists.txt b/deps/llhttp/CMakeLists.txt index 87a66929dbe036..56f0098c2c5c49 100644 --- a/deps/llhttp/CMakeLists.txt +++ b/deps/llhttp/CMakeLists.txt @@ -1,7 +1,7 @@ -cmake_minimum_required(VERSION 3.5.1) +cmake_minimum_required(VERSION 3.25.0) cmake_policy(SET CMP0069 NEW) -project(llhttp VERSION 9.2.1) +project(llhttp VERSION 9.3.0) include(GNUInstallDirs) set(CMAKE_C_STANDARD 99) @@ -49,7 +49,7 @@ function(config_library target) target_include_directories(${target} PUBLIC $ - $ + $ ) set_target_properties(${target} PROPERTIES @@ -61,6 +61,7 @@ function(config_library target) install(TARGETS ${target} EXPORT llhttp + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} diff --git a/deps/llhttp/LICENSE b/deps/llhttp/LICENSE new file mode 100644 index 00000000000000..6c1512dd6bcd6d --- /dev/null +++ b/deps/llhttp/LICENSE @@ -0,0 +1,22 @@ +This software is licensed under the MIT License. + +Copyright Fedor Indutny, 2018. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to permit +persons to whom the Software is furnished to do so, subject to the +following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/deps/llhttp/README.md b/deps/llhttp/README.md index 28653aa0358415..70af44ff0f5a16 100644 --- a/deps/llhttp/README.md +++ b/deps/llhttp/README.md @@ -94,7 +94,7 @@ int main() { if (err == HPE_OK) { fprintf(stdout, "Successfully parsed!\n"); } else { - fprintf(stderr, "Parse error: %s %s\n", llhttp_errno_name(err), parser.reason); + fprintf(stderr, "Parse error: %s %s\n", llhttp_errno_name(err), llhttp_get_error_reason(&parser)); } } ``` @@ -112,6 +112,7 @@ The following callbacks can return `0` (proceed normally), `-1` (error) or `HPE_ * `on_message_complete`: Invoked when a request/response has been completedly parsed. * `on_url_complete`: Invoked after the URL has been parsed. * `on_method_complete`: Invoked after the HTTP method has been parsed. +* `on_protocol_complete`: Invoked after the HTTP version has been parsed. * `on_version_complete`: Invoked after the HTTP version has been parsed. * `on_status_complete`: Invoked after the status code has been parsed. * `on_header_field_complete`: Invoked after a header name has been parsed. @@ -130,6 +131,7 @@ The following callbacks can return `0` (proceed normally), `-1` (error) or `HPE_ * `on_method`: Invoked when another character of the method is received. When parser is created with `HTTP_BOTH` and the input is a response, this also invoked for the sequence `HTTP/` of the first message. +* `on_protocol`: Invoked when another character of the protocol is received. * `on_version`: Invoked when another character of the version is received. * `on_header_field`: Invoked when another character of a header name is received. * `on_header_value`: Invoked when another character of a header value is received. @@ -187,7 +189,8 @@ Parse full or partial request/response, invoking user callbacks along the way. If any of `llhttp_data_cb` returns errno not equal to `HPE_OK` - the parsing interrupts, and such errno is returned from `llhttp_execute()`. If `HPE_PAUSED` was used as a errno, -the execution can be resumed with `llhttp_resume()` call. +the execution can be resumed with `llhttp_resume()` call. In that case the input should be advanced +to the last processed byte from the parser, which can be obtained via `llhttp_get_error_pos()`. In a special case of CONNECT/Upgrade request/response `HPE_PAUSED_UPGRADE` is returned after fully parsing the request/response. If the user wishes to continue parsing, @@ -196,6 +199,8 @@ they need to invoke `llhttp_resume_after_upgrade()`. **if this function ever returns a non-pause type error, it will continue to return the same error upon each successive call up until `llhttp_init()` is called.** +If this function returns `HPE_OK`, it means all the input has been consumed and parsed. + ### `llhttp_errno_t llhttp_finish(llhttp_t* parser)` This method should be called when the other side has no further bytes to diff --git a/deps/llhttp/include/llhttp.h b/deps/llhttp/include/llhttp.h index 37b7934d2ee7bc..60544596a9942c 100644 --- a/deps/llhttp/include/llhttp.h +++ b/deps/llhttp/include/llhttp.h @@ -3,8 +3,8 @@ #define INCLUDE_LLHTTP_H_ #define LLHTTP_VERSION_MAJOR 9 -#define LLHTTP_VERSION_MINOR 2 -#define LLHTTP_VERSION_PATCH 1 +#define LLHTTP_VERSION_MINOR 3 +#define LLHTTP_VERSION_PATCH 0 #ifndef INCLUDE_LLHTTP_ITSELF_H_ #define INCLUDE_LLHTTP_ITSELF_H_ @@ -90,7 +90,8 @@ enum llhttp_errno { HPE_CB_HEADER_VALUE_COMPLETE = 29, HPE_CB_CHUNK_EXTENSION_NAME_COMPLETE = 34, HPE_CB_CHUNK_EXTENSION_VALUE_COMPLETE = 35, - HPE_CB_RESET = 31 + HPE_CB_RESET = 31, + HPE_CB_PROTOCOL_COMPLETE = 38 }; typedef enum llhttp_errno llhttp_errno_t; @@ -326,6 +327,7 @@ typedef enum llhttp_status llhttp_status_t; XX(34, CB_CHUNK_EXTENSION_NAME_COMPLETE, CB_CHUNK_EXTENSION_NAME_COMPLETE) \ XX(35, CB_CHUNK_EXTENSION_VALUE_COMPLETE, CB_CHUNK_EXTENSION_VALUE_COMPLETE) \ XX(31, CB_RESET, CB_RESET) \ + XX(38, CB_PROTOCOL_COMPLETE, CB_PROTOCOL_COMPLETE) \ #define HTTP_METHOD_MAP(XX) \ @@ -567,6 +569,7 @@ struct llhttp_settings_s { llhttp_cb on_message_begin; /* Possible return values 0, -1, HPE_USER */ + llhttp_data_cb on_protocol; llhttp_data_cb on_url; llhttp_data_cb on_status; llhttp_data_cb on_method; @@ -592,6 +595,7 @@ struct llhttp_settings_s { /* Possible return values 0, -1, `HPE_PAUSED` */ llhttp_cb on_message_complete; + llhttp_cb on_protocol_complete; llhttp_cb on_url_complete; llhttp_cb on_status_complete; llhttp_cb on_method_complete; diff --git a/deps/llhttp/libllhttp.pc.in b/deps/llhttp/libllhttp.pc.in index 67d280a830dcc9..4ad300b7409739 100644 --- a/deps/llhttp/libllhttp.pc.in +++ b/deps/llhttp/libllhttp.pc.in @@ -1,10 +1,10 @@ prefix=@CMAKE_INSTALL_PREFIX@ -exec_prefix=@CMAKE_INSTALL_PREFIX@ -libdir=@CMAKE_INSTALL_PREFIX@/@CMAKE_INSTALL_LIBDIR@ -includedir=@CMAKE_INSTALL_PREFIX@/@CMAKE_INSTALL_INCLUDEDIR@ +exec_prefix=@CMAKE_INSTALL_FULL_BINDIR@ +libdir=@CMAKE_INSTALL_FULL_LIBDIR@ +includedir=@CMAKE_INSTALL_FULL_INCLUDEDIR@ Name: libllhttp Description: Node.js llhttp Library Version: @PROJECT_VERSION@ Libs: -L${libdir} -lllhttp -Cflags: -I${includedir} \ No newline at end of file +Cflags: -I${includedir} diff --git a/deps/llhttp/src/api.c b/deps/llhttp/src/api.c index 8c2ce3dc5c455b..0245254177ac8c 100644 --- a/deps/llhttp/src/api.c +++ b/deps/llhttp/src/api.c @@ -57,29 +57,14 @@ static int wasm_on_headers_complete_wrap(llhttp_t* p) { } const llhttp_settings_t wasm_settings = { - wasm_on_message_begin, - wasm_on_url, - wasm_on_status, - NULL, - NULL, - wasm_on_header_field, - wasm_on_header_value, - NULL, - NULL, - wasm_on_headers_complete_wrap, - wasm_on_body, - wasm_on_message_complete, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, + .on_message_begin = wasm_on_message_begin, + .on_url = wasm_on_url, + .on_status = wasm_on_status, + .on_header_field = wasm_on_header_field, + .on_header_value = wasm_on_header_value, + .on_headers_complete = wasm_on_headers_complete_wrap, + .on_body = wasm_on_body, + .on_message_complete = wasm_on_message_complete, }; @@ -341,6 +326,20 @@ int llhttp__on_message_begin(llhttp_t* s, const char* p, const char* endp) { } +int llhttp__on_protocol(llhttp_t* s, const char* p, const char* endp) { + int err; + SPAN_CALLBACK_MAYBE(s, on_protocol, p, endp - p); + return err; +} + + +int llhttp__on_protocol_complete(llhttp_t* s, const char* p, const char* endp) { + int err; + CALLBACK_MAYBE(s, on_protocol_complete); + return err; +} + + int llhttp__on_url(llhttp_t* s, const char* p, const char* endp) { int err; SPAN_CALLBACK_MAYBE(s, on_url, p, endp - p); diff --git a/deps/llhttp/src/llhttp.c b/deps/llhttp/src/llhttp.c index 3ef3b817f3d9ce..aa4c468209700c 100644 --- a/deps/llhttp/src/llhttp.c +++ b/deps/llhttp/src/llhttp.c @@ -10,10 +10,20 @@ #endif /* _MSC_VER */ #endif /* __SSE4_2__ */ +#ifdef __ARM_NEON__ + #include +#endif /* __ARM_NEON__ */ + +#ifdef __wasm__ + #include +#endif /* __wasm__ */ + #ifdef _MSC_VER #define ALIGN(n) _declspec(align(n)) + #define UNREACHABLE __assume(0) #else /* !_MSC_VER */ #define ALIGN(n) __attribute__((aligned(n))) + #define UNREACHABLE __builtin_unreachable() #endif /* _MSC_VER */ #include "llhttp.h" @@ -72,16 +82,16 @@ static const unsigned char llparse_blob12[] = { 'p', 'g', 'r', 'a', 'd', 'e' }; static const unsigned char llparse_blob13[] = { - 'T', 'T', 'P', '/' + 'T', 'T', 'P' }; static const unsigned char llparse_blob14[] = { 0xd, 0xa, 0xd, 0xa, 'S', 'M', 0xd, 0xa, 0xd, 0xa }; static const unsigned char llparse_blob15[] = { - 'C', 'E', '/' + 'C', 'E' }; static const unsigned char llparse_blob16[] = { - 'T', 'S', 'P', '/' + 'T', 'S', 'P' }; static const unsigned char llparse_blob17[] = { 'N', 'O', 'U', 'N', 'C', 'E' @@ -207,12 +217,18 @@ static const unsigned char llparse_blob57[] = { 'U', 'B', 'S', 'C', 'R', 'I', 'B', 'E' }; static const unsigned char llparse_blob58[] = { - 'H', 'T', 'T', 'P', '/' + 'T', 'T', 'P' }; static const unsigned char llparse_blob59[] = { - 'A', 'D' + 'C', 'E' }; static const unsigned char llparse_blob60[] = { + 'T', 'S', 'P' +}; +static const unsigned char llparse_blob61[] = { + 'A', 'D' +}; +static const unsigned char llparse_blob62[] = { 'T', 'P', '/' }; @@ -425,17 +441,27 @@ enum llparse_state_e { s_n_llhttp__internal__n_req_http_complete, s_n_llhttp__internal__n_invoke_load_method_1, s_n_llhttp__internal__n_invoke_llhttp__on_version_complete, - s_n_llhttp__internal__n_error_66, - s_n_llhttp__internal__n_error_73, - s_n_llhttp__internal__n_req_http_minor, + s_n_llhttp__internal__n_error_67, s_n_llhttp__internal__n_error_74, - s_n_llhttp__internal__n_req_http_dot, + s_n_llhttp__internal__n_req_http_minor, s_n_llhttp__internal__n_error_75, + s_n_llhttp__internal__n_req_http_dot, + s_n_llhttp__internal__n_error_76, s_n_llhttp__internal__n_req_http_major, s_n_llhttp__internal__n_span_start_llhttp__on_version, - s_n_llhttp__internal__n_req_http_start_1, - s_n_llhttp__internal__n_req_http_start_2, - s_n_llhttp__internal__n_req_http_start_3, + s_n_llhttp__internal__n_req_after_protocol, + s_n_llhttp__internal__n_invoke_load_method, + s_n_llhttp__internal__n_invoke_llhttp__on_protocol_complete, + s_n_llhttp__internal__n_error_82, + s_n_llhttp__internal__n_req_after_http_start_1, + s_n_llhttp__internal__n_invoke_load_method_2, + s_n_llhttp__internal__n_invoke_llhttp__on_protocol_complete_1, + s_n_llhttp__internal__n_req_after_http_start_2, + s_n_llhttp__internal__n_invoke_load_method_3, + s_n_llhttp__internal__n_invoke_llhttp__on_protocol_complete_2, + s_n_llhttp__internal__n_req_after_http_start_3, + s_n_llhttp__internal__n_req_after_http_start, + s_n_llhttp__internal__n_span_start_llhttp__on_protocol, s_n_llhttp__internal__n_req_http_start, s_n_llhttp__internal__n_url_to_http, s_n_llhttp__internal__n_url_skip_to_http, @@ -543,15 +569,22 @@ enum llparse_state_e { s_n_llhttp__internal__n_res_status_code_digit_1, s_n_llhttp__internal__n_res_after_version, s_n_llhttp__internal__n_invoke_llhttp__on_version_complete_1, - s_n_llhttp__internal__n_error_89, - s_n_llhttp__internal__n_error_103, + s_n_llhttp__internal__n_error_93, + s_n_llhttp__internal__n_error_107, s_n_llhttp__internal__n_res_http_minor, - s_n_llhttp__internal__n_error_104, + s_n_llhttp__internal__n_error_108, s_n_llhttp__internal__n_res_http_dot, - s_n_llhttp__internal__n_error_105, + s_n_llhttp__internal__n_error_109, s_n_llhttp__internal__n_res_http_major, s_n_llhttp__internal__n_span_start_llhttp__on_version_1, - s_n_llhttp__internal__n_start_res, + s_n_llhttp__internal__n_res_after_protocol, + s_n_llhttp__internal__n_invoke_llhttp__on_protocol_complete_3, + s_n_llhttp__internal__n_error_115, + s_n_llhttp__internal__n_res_after_start_1, + s_n_llhttp__internal__n_res_after_start_2, + s_n_llhttp__internal__n_res_after_start_3, + s_n_llhttp__internal__n_res_after_start, + s_n_llhttp__internal__n_span_start_llhttp__on_protocol_1, s_n_llhttp__internal__n_invoke_llhttp__on_method_complete, s_n_llhttp__internal__n_req_or_res_method_2, s_n_llhttp__internal__n_invoke_update_type_1, @@ -574,6 +607,10 @@ int llhttp__on_url( llhttp__internal_t* s, const unsigned char* p, const unsigned char* endp); +int llhttp__on_protocol( + llhttp__internal_t* s, const unsigned char* p, + const unsigned char* endp); + int llhttp__on_version( llhttp__internal_t* s, const unsigned char* p, const unsigned char* endp); @@ -1057,6 +1094,10 @@ int llhttp__internal__c_or_flags_20( return 0; } +int llhttp__on_protocol_complete( + llhttp__internal_t* s, const unsigned char* p, + const unsigned char* endp); + int llhttp__internal__c_load_method( llhttp__internal_t* state, const unsigned char* p, @@ -1192,8 +1233,7 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_invoke_test_lenient_flags_3; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_invoke_llhttp__after_message_complete: s_n_llhttp__internal__n_invoke_llhttp__after_message_complete: { @@ -1203,8 +1243,7 @@ static llparse_state_t llhttp__internal__run( default: goto s_n_llhttp__internal__n_invoke_update_finish_1; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_pause_1: s_n_llhttp__internal__n_pause_1: { @@ -1213,8 +1252,7 @@ static llparse_state_t llhttp__internal__run( state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__after_message_complete; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_invoke_is_equal_upgrade: s_n_llhttp__internal__n_invoke_is_equal_upgrade: { @@ -1224,8 +1262,7 @@ static llparse_state_t llhttp__internal__run( default: goto s_n_llhttp__internal__n_pause_1; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_invoke_llhttp__on_message_complete_2: s_n_llhttp__internal__n_invoke_llhttp__on_message_complete_2: { @@ -1237,8 +1274,7 @@ static llparse_state_t llhttp__internal__run( default: goto s_n_llhttp__internal__n_error_38; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_chunk_data_almost_done_1: s_n_llhttp__internal__n_chunk_data_almost_done_1: { @@ -1254,8 +1290,7 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_invoke_test_lenient_flags_7; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_chunk_data_almost_done: s_n_llhttp__internal__n_chunk_data_almost_done: { @@ -1275,8 +1310,7 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_invoke_test_lenient_flags_7; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_consume_content_length: s_n_llhttp__internal__n_consume_content_length: { @@ -1293,8 +1327,7 @@ static llparse_state_t llhttp__internal__run( state->content_length -= avail; return s_n_llhttp__internal__n_consume_content_length; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_span_start_llhttp__on_body: s_n_llhttp__internal__n_span_start_llhttp__on_body: { @@ -1304,8 +1337,7 @@ static llparse_state_t llhttp__internal__run( state->_span_pos0 = (void*) p; state->_span_cb0 = llhttp__on_body; goto s_n_llhttp__internal__n_consume_content_length; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_invoke_is_equal_content_length: s_n_llhttp__internal__n_invoke_is_equal_content_length: { @@ -1315,8 +1347,7 @@ static llparse_state_t llhttp__internal__run( default: goto s_n_llhttp__internal__n_invoke_or_flags; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_chunk_size_almost_done: s_n_llhttp__internal__n_chunk_size_almost_done: { @@ -1332,8 +1363,7 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_invoke_test_lenient_flags_8; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_invoke_test_lenient_flags_9: s_n_llhttp__internal__n_invoke_test_lenient_flags_9: { @@ -1343,8 +1373,7 @@ static llparse_state_t llhttp__internal__run( default: goto s_n_llhttp__internal__n_error_20; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_name_complete: s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_name_complete: { @@ -1356,8 +1385,7 @@ static llparse_state_t llhttp__internal__run( default: goto s_n_llhttp__internal__n_error_19; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_name_complete_1: s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_name_complete_1: { @@ -1369,8 +1397,7 @@ static llparse_state_t llhttp__internal__run( default: goto s_n_llhttp__internal__n_error_21; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_name_complete_2: s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_name_complete_2: { @@ -1382,8 +1409,7 @@ static llparse_state_t llhttp__internal__run( default: goto s_n_llhttp__internal__n_error_22; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_invoke_test_lenient_flags_10: s_n_llhttp__internal__n_invoke_test_lenient_flags_10: { @@ -1393,8 +1419,7 @@ static llparse_state_t llhttp__internal__run( default: goto s_n_llhttp__internal__n_error_25; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_value_complete: s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_value_complete: { @@ -1406,8 +1431,7 @@ static llparse_state_t llhttp__internal__run( default: goto s_n_llhttp__internal__n_error_24; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_value_complete_1: s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_value_complete_1: { @@ -1419,8 +1443,7 @@ static llparse_state_t llhttp__internal__run( default: goto s_n_llhttp__internal__n_error_26; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_chunk_extension_quoted_value_done: s_n_llhttp__internal__n_chunk_extension_quoted_value_done: { @@ -1443,8 +1466,7 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_error_29; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_value_complete_2: s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_value_complete_2: { @@ -1456,8 +1478,7 @@ static llparse_state_t llhttp__internal__run( default: goto s_n_llhttp__internal__n_error_27; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_error_30: s_n_llhttp__internal__n_error_30: { @@ -1466,8 +1487,7 @@ static llparse_state_t llhttp__internal__run( state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_chunk_extension_quoted_value_quoted_pair: s_n_llhttp__internal__n_chunk_extension_quoted_value_quoted_pair: { @@ -1501,8 +1521,7 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_span_end_llhttp__on_chunk_extension_value_3; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_error_31: s_n_llhttp__internal__n_error_31: { @@ -1511,8 +1530,7 @@ static llparse_state_t llhttp__internal__run( state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_chunk_extension_quoted_value: s_n_llhttp__internal__n_chunk_extension_quoted_value: { @@ -1554,8 +1572,7 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_span_end_llhttp__on_chunk_extension_value_4; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_value_complete_3: s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_value_complete_3: { @@ -1567,8 +1584,7 @@ static llparse_state_t llhttp__internal__run( default: goto s_n_llhttp__internal__n_error_32; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_error_33: s_n_llhttp__internal__n_error_33: { @@ -1577,8 +1593,7 @@ static llparse_state_t llhttp__internal__run( state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_chunk_extension_value: s_n_llhttp__internal__n_chunk_extension_value: { @@ -1625,8 +1640,7 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_span_end_llhttp__on_chunk_extension_value_6; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_span_start_llhttp__on_chunk_extension_value: s_n_llhttp__internal__n_span_start_llhttp__on_chunk_extension_value: { @@ -1636,8 +1650,7 @@ static llparse_state_t llhttp__internal__run( state->_span_pos0 = (void*) p; state->_span_cb0 = llhttp__on_chunk_extension_value; goto s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_name_complete_3; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_error_34: s_n_llhttp__internal__n_error_34: { @@ -1646,8 +1659,7 @@ static llparse_state_t llhttp__internal__run( state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_chunk_extension_name: s_n_llhttp__internal__n_chunk_extension_name: { @@ -1693,8 +1705,7 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_span_end_llhttp__on_chunk_extension_name_4; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_span_start_llhttp__on_chunk_extension_name: s_n_llhttp__internal__n_span_start_llhttp__on_chunk_extension_name: { @@ -1704,8 +1715,7 @@ static llparse_state_t llhttp__internal__run( state->_span_pos0 = (void*) p; state->_span_cb0 = llhttp__on_chunk_extension_name; goto s_n_llhttp__internal__n_chunk_extension_name; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_chunk_extensions: s_n_llhttp__internal__n_chunk_extensions: { @@ -1725,8 +1735,7 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_span_start_llhttp__on_chunk_extension_name; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_chunk_size_otherwise: s_n_llhttp__internal__n_chunk_size_otherwise: { @@ -1758,8 +1767,7 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_error_35; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_chunk_size: s_n_llhttp__internal__n_chunk_size: { @@ -1881,8 +1889,7 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_chunk_size_otherwise; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_chunk_size_digit: s_n_llhttp__internal__n_chunk_size_digit: { @@ -2004,8 +2011,7 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_error_37; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_invoke_update_content_length_1: s_n_llhttp__internal__n_invoke_update_content_length_1: { @@ -2013,8 +2019,7 @@ static llparse_state_t llhttp__internal__run( default: goto s_n_llhttp__internal__n_chunk_size_digit; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_consume_content_length_1: s_n_llhttp__internal__n_consume_content_length_1: { @@ -2031,8 +2036,7 @@ static llparse_state_t llhttp__internal__run( state->content_length -= avail; return s_n_llhttp__internal__n_consume_content_length_1; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_span_start_llhttp__on_body_1: s_n_llhttp__internal__n_span_start_llhttp__on_body_1: { @@ -2042,8 +2046,7 @@ static llparse_state_t llhttp__internal__run( state->_span_pos0 = (void*) p; state->_span_cb0 = llhttp__on_body; goto s_n_llhttp__internal__n_consume_content_length_1; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_eof: s_n_llhttp__internal__n_eof: { @@ -2052,8 +2055,7 @@ static llparse_state_t llhttp__internal__run( } p++; goto s_n_llhttp__internal__n_eof; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_span_start_llhttp__on_body_2: s_n_llhttp__internal__n_span_start_llhttp__on_body_2: { @@ -2063,8 +2065,7 @@ static llparse_state_t llhttp__internal__run( state->_span_pos0 = (void*) p; state->_span_cb0 = llhttp__on_body; goto s_n_llhttp__internal__n_eof; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_invoke_llhttp__after_headers_complete: s_n_llhttp__internal__n_invoke_llhttp__after_headers_complete: { @@ -2082,8 +2083,7 @@ static llparse_state_t llhttp__internal__run( default: goto s_n_llhttp__internal__n_invoke_llhttp__on_message_complete; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_error_5: s_n_llhttp__internal__n_error_5: { @@ -2092,8 +2092,7 @@ static llparse_state_t llhttp__internal__run( state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_headers_almost_done: s_n_llhttp__internal__n_headers_almost_done: { @@ -2109,8 +2108,7 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_invoke_test_lenient_flags_12; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_header_field_colon_discard_ws: s_n_llhttp__internal__n_header_field_colon_discard_ws: { @@ -2126,8 +2124,7 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_header_field_colon; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_invoke_llhttp__on_header_value_complete: s_n_llhttp__internal__n_invoke_llhttp__on_header_value_complete: { @@ -2139,8 +2136,7 @@ static llparse_state_t llhttp__internal__run( default: goto s_n_llhttp__internal__n_error_48; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_span_start_llhttp__on_header_value: s_n_llhttp__internal__n_span_start_llhttp__on_header_value: { @@ -2150,8 +2146,7 @@ static llparse_state_t llhttp__internal__run( state->_span_pos0 = (void*) p; state->_span_cb0 = llhttp__on_header_value; goto s_n_llhttp__internal__n_span_end_llhttp__on_header_value; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_header_value_discard_lws: s_n_llhttp__internal__n_header_value_discard_lws: { @@ -2171,8 +2166,7 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_invoke_load_header_state_1; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_header_value_discard_ws_almost_done: s_n_llhttp__internal__n_header_value_discard_ws_almost_done: { @@ -2188,8 +2182,7 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_invoke_test_lenient_flags_16; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_header_value_lws: s_n_llhttp__internal__n_header_value_lws: { @@ -2207,8 +2200,7 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_invoke_load_header_state_5; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_header_value_almost_done: s_n_llhttp__internal__n_header_value_almost_done: { @@ -2224,8 +2216,7 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_error_53; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_invoke_test_lenient_flags_17: s_n_llhttp__internal__n_invoke_test_lenient_flags_17: { @@ -2235,8 +2226,7 @@ static llparse_state_t llhttp__internal__run( default: goto s_n_llhttp__internal__n_error_51; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_header_value_lenient: s_n_llhttp__internal__n_header_value_lenient: { @@ -2255,8 +2245,7 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_header_value_lenient; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_error_54: s_n_llhttp__internal__n_error_54: { @@ -2265,8 +2254,7 @@ static llparse_state_t llhttp__internal__run( state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_header_value_otherwise: s_n_llhttp__internal__n_header_value_otherwise: { @@ -2284,8 +2272,7 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_invoke_test_lenient_flags_19; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_header_value_connection_token: s_n_llhttp__internal__n_header_value_connection_token: { @@ -2323,8 +2310,7 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_header_value_otherwise; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_header_value_connection_ws: s_n_llhttp__internal__n_header_value_connection_ws: { @@ -2350,8 +2336,7 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_invoke_update_header_state_5; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_header_value_connection_1: s_n_llhttp__internal__n_header_value_connection_1: { @@ -2374,8 +2359,7 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_header_value_connection_token; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_header_value_connection_2: s_n_llhttp__internal__n_header_value_connection_2: { @@ -2398,8 +2382,7 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_header_value_connection_token; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_header_value_connection_3: s_n_llhttp__internal__n_header_value_connection_3: { @@ -2422,8 +2405,7 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_header_value_connection_token; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_header_value_connection: s_n_llhttp__internal__n_header_value_connection: { @@ -2455,8 +2437,7 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_header_value_connection_token; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_error_56: s_n_llhttp__internal__n_error_56: { @@ -2465,8 +2446,7 @@ static llparse_state_t llhttp__internal__run( state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_error_57: s_n_llhttp__internal__n_error_57: { @@ -2475,8 +2455,7 @@ static llparse_state_t llhttp__internal__run( state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_header_value_content_length_ws: s_n_llhttp__internal__n_header_value_content_length_ws: { @@ -2498,8 +2477,7 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_span_end_llhttp__on_header_value_7; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_header_value_content_length: s_n_llhttp__internal__n_header_value_content_length: { @@ -2561,8 +2539,7 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_header_value_content_length_ws; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_error_59: s_n_llhttp__internal__n_error_59: { @@ -2571,8 +2548,7 @@ static llparse_state_t llhttp__internal__run( state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_error_58: s_n_llhttp__internal__n_error_58: { @@ -2581,8 +2557,7 @@ static llparse_state_t llhttp__internal__run( state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_header_value_te_token_ows: s_n_llhttp__internal__n_header_value_te_token_ows: { @@ -2602,8 +2577,7 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_header_value_te_chunked; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_header_value: s_n_llhttp__internal__n_header_value: { @@ -2632,7 +2606,6 @@ static llparse_state_t llhttp__internal__run( if (endp - p >= 16) { __m128i ranges; __m128i input; - int avail; int match_len; /* Load input */ @@ -2652,6 +2625,78 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_header_value_otherwise; } #endif /* __SSE4_2__ */ + #ifdef __ARM_NEON__ + while (endp - p >= 16) { + uint8x16_t input; + uint8x16_t single; + uint8x16_t mask; + uint8x8_t narrow; + uint64_t match_mask; + int match_len; + + /* Load input */ + input = vld1q_u8(p); + /* Find first character that does not match `ranges` */ + single = vceqq_u8(input, vdupq_n_u8(0x9)); + mask = single; + single = vandq_u16( + vcgeq_u8(input, vdupq_n_u8(' ')), + vcleq_u8(input, vdupq_n_u8('~')) + ); + mask = vorrq_u16(mask, single); + single = vandq_u16( + vcgeq_u8(input, vdupq_n_u8(0x80)), + vcleq_u8(input, vdupq_n_u8(0xff)) + ); + mask = vorrq_u16(mask, single); + narrow = vshrn_n_u16(mask, 4); + match_mask = ~vget_lane_u64(vreinterpret_u64_u8(narrow), 0); + match_len = __builtin_ctzll(match_mask) >> 2; + if (match_len != 16) { + p += match_len; + goto s_n_llhttp__internal__n_header_value_otherwise; + } + p += 16; + } + if (p == endp) { + return s_n_llhttp__internal__n_header_value; + } + #endif /* __ARM_NEON__ */ + #ifdef __wasm_simd128__ + while (endp - p >= 16) { + v128_t input; + v128_t mask; + v128_t single; + int match_len; + + /* Load input */ + input = wasm_v128_load(p); + /* Find first character that does not match `ranges` */ + single = wasm_i8x16_eq(input, wasm_u8x16_const_splat(0x9)); + mask = single; + single = wasm_v128_and( + wasm_i8x16_ge(input, wasm_u8x16_const_splat(' ')), + wasm_i8x16_le(input, wasm_u8x16_const_splat('~')) + ); + mask = wasm_v128_or(mask, single); + single = wasm_v128_and( + wasm_i8x16_ge(input, wasm_u8x16_const_splat(0x80)), + wasm_i8x16_le(input, wasm_u8x16_const_splat(0xff)) + ); + mask = wasm_v128_or(mask, single); + match_len = __builtin_ctz( + ~wasm_i8x16_bitmask(mask) + ); + if (match_len != 16) { + p += match_len; + goto s_n_llhttp__internal__n_header_value_otherwise; + } + p += 16; + } + if (p == endp) { + return s_n_llhttp__internal__n_header_value; + } + #endif /* __wasm_simd128__ */ switch (lookup_table[(uint8_t) *p]) { case 1: { p++; @@ -2661,8 +2706,7 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_header_value_otherwise; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_header_value_te_token: s_n_llhttp__internal__n_header_value_te_token: { @@ -2700,8 +2744,7 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_invoke_update_header_state_9; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_header_value_te_chunked_last: s_n_llhttp__internal__n_header_value_te_chunked_last: { @@ -2726,8 +2769,7 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_header_value_te_token; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_header_value_te_chunked: s_n_llhttp__internal__n_header_value_te_chunked: { @@ -2750,8 +2792,7 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_header_value_te_token; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_span_start_llhttp__on_header_value_1: s_n_llhttp__internal__n_span_start_llhttp__on_header_value_1: { @@ -2761,8 +2802,7 @@ static llparse_state_t llhttp__internal__run( state->_span_pos0 = (void*) p; state->_span_cb0 = llhttp__on_header_value; goto s_n_llhttp__internal__n_invoke_load_header_state_3; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_header_value_discard_ws: s_n_llhttp__internal__n_header_value_discard_ws: { @@ -2790,8 +2830,7 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_span_start_llhttp__on_header_value_1; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_invoke_load_header_state: s_n_llhttp__internal__n_invoke_load_header_state: { @@ -2803,8 +2842,7 @@ static llparse_state_t llhttp__internal__run( default: goto s_n_llhttp__internal__n_header_value_discard_ws; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_invoke_llhttp__on_header_field_complete: s_n_llhttp__internal__n_invoke_llhttp__on_header_field_complete: { @@ -2816,8 +2854,7 @@ static llparse_state_t llhttp__internal__run( default: goto s_n_llhttp__internal__n_error_45; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_header_field_general_otherwise: s_n_llhttp__internal__n_header_field_general_otherwise: { @@ -2832,8 +2869,7 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_error_62; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_header_field_general: s_n_llhttp__internal__n_header_field_general: { @@ -2862,7 +2898,6 @@ static llparse_state_t llhttp__internal__run( if (endp - p >= 16) { __m128i ranges; __m128i input; - int avail; int match_len; /* Load input */ @@ -2903,8 +2938,7 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_header_field_general_otherwise; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_header_field_colon: s_n_llhttp__internal__n_header_field_colon: { @@ -2922,8 +2956,7 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_invoke_update_header_state_10; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_header_field_3: s_n_llhttp__internal__n_header_field_3: { @@ -2947,8 +2980,7 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_invoke_update_header_state_11; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_header_field_4: s_n_llhttp__internal__n_header_field_4: { @@ -2972,8 +3004,7 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_invoke_update_header_state_11; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_header_field_2: s_n_llhttp__internal__n_header_field_2: { @@ -2993,8 +3024,7 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_invoke_update_header_state_11; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_header_field_1: s_n_llhttp__internal__n_header_field_1: { @@ -3017,8 +3047,7 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_invoke_update_header_state_11; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_header_field_5: s_n_llhttp__internal__n_header_field_5: { @@ -3042,8 +3071,7 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_invoke_update_header_state_11; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_header_field_6: s_n_llhttp__internal__n_header_field_6: { @@ -3067,8 +3095,7 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_invoke_update_header_state_11; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_header_field_7: s_n_llhttp__internal__n_header_field_7: { @@ -3092,8 +3119,7 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_invoke_update_header_state_11; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_header_field: s_n_llhttp__internal__n_header_field: { @@ -3121,8 +3147,7 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_invoke_update_header_state_11; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_span_start_llhttp__on_header_field: s_n_llhttp__internal__n_span_start_llhttp__on_header_field: { @@ -3132,8 +3157,7 @@ static llparse_state_t llhttp__internal__run( state->_span_pos0 = (void*) p; state->_span_cb0 = llhttp__on_header_field; goto s_n_llhttp__internal__n_header_field; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_header_field_start: s_n_llhttp__internal__n_header_field_start: { @@ -3156,8 +3180,7 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_span_start_llhttp__on_header_field; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_headers_start: s_n_llhttp__internal__n_headers_start: { @@ -3173,8 +3196,7 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_header_field_start; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_url_to_http_09: s_n_llhttp__internal__n_url_to_http_09: { @@ -3194,8 +3216,7 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_invoke_update_http_major; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_url_skip_to_http09: s_n_llhttp__internal__n_url_skip_to_http09: { @@ -3216,8 +3237,7 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_url_to_http_09; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_url_skip_lf_to_http09_1: s_n_llhttp__internal__n_url_skip_lf_to_http09_1: { @@ -3233,8 +3253,7 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_error_63; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_url_skip_lf_to_http09: s_n_llhttp__internal__n_url_skip_lf_to_http09: { @@ -3258,8 +3277,7 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_error_63; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_req_pri_upgrade: s_n_llhttp__internal__n_req_pri_upgrade: { @@ -3273,17 +3291,16 @@ static llparse_state_t llhttp__internal__run( switch (match_seq.status) { case kMatchComplete: { p++; - goto s_n_llhttp__internal__n_error_71; + goto s_n_llhttp__internal__n_error_72; } case kMatchPause: { return s_n_llhttp__internal__n_req_pri_upgrade; } case kMatchMismatch: { - goto s_n_llhttp__internal__n_error_72; + goto s_n_llhttp__internal__n_error_73; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_req_http_complete_crlf: s_n_llhttp__internal__n_req_http_complete_crlf: { @@ -3299,8 +3316,7 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_invoke_test_lenient_flags_26; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_req_http_complete: s_n_llhttp__internal__n_req_http_complete: { @@ -3317,11 +3333,10 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_req_http_complete_crlf; } default: { - goto s_n_llhttp__internal__n_error_70; + goto s_n_llhttp__internal__n_error_71; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_invoke_load_method_1: s_n_llhttp__internal__n_invoke_load_method_1: { @@ -3331,8 +3346,7 @@ static llparse_state_t llhttp__internal__run( default: goto s_n_llhttp__internal__n_req_http_complete; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_invoke_llhttp__on_version_complete: s_n_llhttp__internal__n_invoke_llhttp__on_version_complete: { @@ -3342,30 +3356,27 @@ static llparse_state_t llhttp__internal__run( case 21: goto s_n_llhttp__internal__n_pause_21; default: - goto s_n_llhttp__internal__n_error_67; + goto s_n_llhttp__internal__n_error_68; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } - case s_n_llhttp__internal__n_error_66: - s_n_llhttp__internal__n_error_66: { + case s_n_llhttp__internal__n_error_67: + s_n_llhttp__internal__n_error_67: { state->error = 0x9; state->reason = "Invalid HTTP version"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } - case s_n_llhttp__internal__n_error_73: - s_n_llhttp__internal__n_error_73: { + case s_n_llhttp__internal__n_error_74: + s_n_llhttp__internal__n_error_74: { state->error = 0x9; state->reason = "Invalid minor version"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_req_http_minor: s_n_llhttp__internal__n_req_http_minor: { @@ -3427,18 +3438,16 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_span_end_llhttp__on_version_2; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } - case s_n_llhttp__internal__n_error_74: - s_n_llhttp__internal__n_error_74: { + case s_n_llhttp__internal__n_error_75: + s_n_llhttp__internal__n_error_75: { state->error = 0x9; state->reason = "Expected dot"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_req_http_dot: s_n_llhttp__internal__n_req_http_dot: { @@ -3454,18 +3463,16 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_span_end_llhttp__on_version_3; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } - case s_n_llhttp__internal__n_error_75: - s_n_llhttp__internal__n_error_75: { + case s_n_llhttp__internal__n_error_76: + s_n_llhttp__internal__n_error_76: { state->error = 0x9; state->reason = "Invalid major version"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_req_http_major: s_n_llhttp__internal__n_req_http_major: { @@ -3527,8 +3534,7 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_span_end_llhttp__on_version_4; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_span_start_llhttp__on_version: s_n_llhttp__internal__n_span_start_llhttp__on_version: { @@ -3538,109 +3544,313 @@ static llparse_state_t llhttp__internal__run( state->_span_pos0 = (void*) p; state->_span_cb0 = llhttp__on_version; goto s_n_llhttp__internal__n_req_http_major; - /* UNREACHABLE */; - abort(); + UNREACHABLE; + } + case s_n_llhttp__internal__n_req_after_protocol: + s_n_llhttp__internal__n_req_after_protocol: { + if (p == endp) { + return s_n_llhttp__internal__n_req_after_protocol; + } + switch (*p) { + case '/': { + p++; + goto s_n_llhttp__internal__n_span_start_llhttp__on_version; + } + default: { + goto s_n_llhttp__internal__n_error_77; + } + } + UNREACHABLE; + } + case s_n_llhttp__internal__n_invoke_load_method: + s_n_llhttp__internal__n_invoke_load_method: { + switch (llhttp__internal__c_load_method(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_req_after_protocol; + case 1: + goto s_n_llhttp__internal__n_req_after_protocol; + case 2: + goto s_n_llhttp__internal__n_req_after_protocol; + case 3: + goto s_n_llhttp__internal__n_req_after_protocol; + case 4: + goto s_n_llhttp__internal__n_req_after_protocol; + case 5: + goto s_n_llhttp__internal__n_req_after_protocol; + case 6: + goto s_n_llhttp__internal__n_req_after_protocol; + case 7: + goto s_n_llhttp__internal__n_req_after_protocol; + case 8: + goto s_n_llhttp__internal__n_req_after_protocol; + case 9: + goto s_n_llhttp__internal__n_req_after_protocol; + case 10: + goto s_n_llhttp__internal__n_req_after_protocol; + case 11: + goto s_n_llhttp__internal__n_req_after_protocol; + case 12: + goto s_n_llhttp__internal__n_req_after_protocol; + case 13: + goto s_n_llhttp__internal__n_req_after_protocol; + case 14: + goto s_n_llhttp__internal__n_req_after_protocol; + case 15: + goto s_n_llhttp__internal__n_req_after_protocol; + case 16: + goto s_n_llhttp__internal__n_req_after_protocol; + case 17: + goto s_n_llhttp__internal__n_req_after_protocol; + case 18: + goto s_n_llhttp__internal__n_req_after_protocol; + case 19: + goto s_n_llhttp__internal__n_req_after_protocol; + case 20: + goto s_n_llhttp__internal__n_req_after_protocol; + case 21: + goto s_n_llhttp__internal__n_req_after_protocol; + case 22: + goto s_n_llhttp__internal__n_req_after_protocol; + case 23: + goto s_n_llhttp__internal__n_req_after_protocol; + case 24: + goto s_n_llhttp__internal__n_req_after_protocol; + case 25: + goto s_n_llhttp__internal__n_req_after_protocol; + case 26: + goto s_n_llhttp__internal__n_req_after_protocol; + case 27: + goto s_n_llhttp__internal__n_req_after_protocol; + case 28: + goto s_n_llhttp__internal__n_req_after_protocol; + case 29: + goto s_n_llhttp__internal__n_req_after_protocol; + case 30: + goto s_n_llhttp__internal__n_req_after_protocol; + case 31: + goto s_n_llhttp__internal__n_req_after_protocol; + case 32: + goto s_n_llhttp__internal__n_req_after_protocol; + case 33: + goto s_n_llhttp__internal__n_req_after_protocol; + case 34: + goto s_n_llhttp__internal__n_req_after_protocol; + case 46: + goto s_n_llhttp__internal__n_req_after_protocol; + default: + goto s_n_llhttp__internal__n_error_66; + } + UNREACHABLE; } - case s_n_llhttp__internal__n_req_http_start_1: - s_n_llhttp__internal__n_req_http_start_1: { + case s_n_llhttp__internal__n_invoke_llhttp__on_protocol_complete: + s_n_llhttp__internal__n_invoke_llhttp__on_protocol_complete: { + switch (llhttp__on_protocol_complete(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_invoke_load_method; + case 21: + goto s_n_llhttp__internal__n_pause_22; + default: + goto s_n_llhttp__internal__n_error_65; + } + UNREACHABLE; + } + case s_n_llhttp__internal__n_error_82: + s_n_llhttp__internal__n_error_82: { + state->error = 0x8; + state->reason = "Expected HTTP/, RTSP/ or ICE/"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + UNREACHABLE; + } + case s_n_llhttp__internal__n_req_after_http_start_1: + s_n_llhttp__internal__n_req_after_http_start_1: { llparse_match_t match_seq; if (p == endp) { - return s_n_llhttp__internal__n_req_http_start_1; + return s_n_llhttp__internal__n_req_after_http_start_1; } - match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob13, 4); + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob13, 3); p = match_seq.current; switch (match_seq.status) { case kMatchComplete: { p++; - goto s_n_llhttp__internal__n_invoke_load_method; + goto s_n_llhttp__internal__n_span_end_llhttp__on_protocol; } case kMatchPause: { - return s_n_llhttp__internal__n_req_http_start_1; + return s_n_llhttp__internal__n_req_after_http_start_1; } case kMatchMismatch: { - goto s_n_llhttp__internal__n_error_78; + goto s_n_llhttp__internal__n_span_end_llhttp__on_protocol_3; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } - case s_n_llhttp__internal__n_req_http_start_2: - s_n_llhttp__internal__n_req_http_start_2: { + case s_n_llhttp__internal__n_invoke_load_method_2: + s_n_llhttp__internal__n_invoke_load_method_2: { + switch (llhttp__internal__c_load_method(state, p, endp)) { + case 33: + goto s_n_llhttp__internal__n_req_after_protocol; + default: + goto s_n_llhttp__internal__n_error_79; + } + UNREACHABLE; + } + case s_n_llhttp__internal__n_invoke_llhttp__on_protocol_complete_1: + s_n_llhttp__internal__n_invoke_llhttp__on_protocol_complete_1: { + switch (llhttp__on_protocol_complete(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_invoke_load_method_2; + case 21: + goto s_n_llhttp__internal__n_pause_23; + default: + goto s_n_llhttp__internal__n_error_78; + } + UNREACHABLE; + } + case s_n_llhttp__internal__n_req_after_http_start_2: + s_n_llhttp__internal__n_req_after_http_start_2: { llparse_match_t match_seq; if (p == endp) { - return s_n_llhttp__internal__n_req_http_start_2; + return s_n_llhttp__internal__n_req_after_http_start_2; } - match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob15, 3); + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob15, 2); p = match_seq.current; switch (match_seq.status) { case kMatchComplete: { p++; - goto s_n_llhttp__internal__n_invoke_load_method_2; + goto s_n_llhttp__internal__n_span_end_llhttp__on_protocol_1; } case kMatchPause: { - return s_n_llhttp__internal__n_req_http_start_2; + return s_n_llhttp__internal__n_req_after_http_start_2; } case kMatchMismatch: { - goto s_n_llhttp__internal__n_error_78; + goto s_n_llhttp__internal__n_span_end_llhttp__on_protocol_3; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; + } + case s_n_llhttp__internal__n_invoke_load_method_3: + s_n_llhttp__internal__n_invoke_load_method_3: { + switch (llhttp__internal__c_load_method(state, p, endp)) { + case 1: + goto s_n_llhttp__internal__n_req_after_protocol; + case 3: + goto s_n_llhttp__internal__n_req_after_protocol; + case 6: + goto s_n_llhttp__internal__n_req_after_protocol; + case 35: + goto s_n_llhttp__internal__n_req_after_protocol; + case 36: + goto s_n_llhttp__internal__n_req_after_protocol; + case 37: + goto s_n_llhttp__internal__n_req_after_protocol; + case 38: + goto s_n_llhttp__internal__n_req_after_protocol; + case 39: + goto s_n_llhttp__internal__n_req_after_protocol; + case 40: + goto s_n_llhttp__internal__n_req_after_protocol; + case 41: + goto s_n_llhttp__internal__n_req_after_protocol; + case 42: + goto s_n_llhttp__internal__n_req_after_protocol; + case 43: + goto s_n_llhttp__internal__n_req_after_protocol; + case 44: + goto s_n_llhttp__internal__n_req_after_protocol; + case 45: + goto s_n_llhttp__internal__n_req_after_protocol; + default: + goto s_n_llhttp__internal__n_error_81; + } + UNREACHABLE; + } + case s_n_llhttp__internal__n_invoke_llhttp__on_protocol_complete_2: + s_n_llhttp__internal__n_invoke_llhttp__on_protocol_complete_2: { + switch (llhttp__on_protocol_complete(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_invoke_load_method_3; + case 21: + goto s_n_llhttp__internal__n_pause_24; + default: + goto s_n_llhttp__internal__n_error_80; + } + UNREACHABLE; } - case s_n_llhttp__internal__n_req_http_start_3: - s_n_llhttp__internal__n_req_http_start_3: { + case s_n_llhttp__internal__n_req_after_http_start_3: + s_n_llhttp__internal__n_req_after_http_start_3: { llparse_match_t match_seq; if (p == endp) { - return s_n_llhttp__internal__n_req_http_start_3; + return s_n_llhttp__internal__n_req_after_http_start_3; } - match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob16, 4); + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob16, 3); p = match_seq.current; switch (match_seq.status) { case kMatchComplete: { p++; - goto s_n_llhttp__internal__n_invoke_load_method_3; + goto s_n_llhttp__internal__n_span_end_llhttp__on_protocol_2; } case kMatchPause: { - return s_n_llhttp__internal__n_req_http_start_3; + return s_n_llhttp__internal__n_req_after_http_start_3; } case kMatchMismatch: { - goto s_n_llhttp__internal__n_error_78; + goto s_n_llhttp__internal__n_span_end_llhttp__on_protocol_3; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } - case s_n_llhttp__internal__n_req_http_start: - s_n_llhttp__internal__n_req_http_start: { + case s_n_llhttp__internal__n_req_after_http_start: + s_n_llhttp__internal__n_req_after_http_start: { if (p == endp) { - return s_n_llhttp__internal__n_req_http_start; + return s_n_llhttp__internal__n_req_after_http_start; } switch (*p) { - case ' ': { - p++; - goto s_n_llhttp__internal__n_req_http_start; - } case 'H': { p++; - goto s_n_llhttp__internal__n_req_http_start_1; + goto s_n_llhttp__internal__n_req_after_http_start_1; } case 'I': { p++; - goto s_n_llhttp__internal__n_req_http_start_2; + goto s_n_llhttp__internal__n_req_after_http_start_2; } case 'R': { p++; - goto s_n_llhttp__internal__n_req_http_start_3; + goto s_n_llhttp__internal__n_req_after_http_start_3; } default: { - goto s_n_llhttp__internal__n_error_78; + goto s_n_llhttp__internal__n_span_end_llhttp__on_protocol_3; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; + } + case s_n_llhttp__internal__n_span_start_llhttp__on_protocol: + s_n_llhttp__internal__n_span_start_llhttp__on_protocol: { + if (p == endp) { + return s_n_llhttp__internal__n_span_start_llhttp__on_protocol; + } + state->_span_pos0 = (void*) p; + state->_span_cb0 = llhttp__on_protocol; + goto s_n_llhttp__internal__n_req_after_http_start; + UNREACHABLE; + } + case s_n_llhttp__internal__n_req_http_start: + s_n_llhttp__internal__n_req_http_start: { + if (p == endp) { + return s_n_llhttp__internal__n_req_http_start; + } + switch (*p) { + case ' ': { + p++; + goto s_n_llhttp__internal__n_req_http_start; + } + default: { + goto s_n_llhttp__internal__n_span_start_llhttp__on_protocol; + } + } + UNREACHABLE; } case s_n_llhttp__internal__n_url_to_http: s_n_llhttp__internal__n_url_to_http: { @@ -3660,8 +3870,7 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_invoke_llhttp__on_url_complete_1; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_url_skip_to_http: s_n_llhttp__internal__n_url_skip_to_http: { @@ -3682,8 +3891,7 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_url_to_http; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_url_fragment: s_n_llhttp__internal__n_url_fragment: { @@ -3727,11 +3935,10 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_url_fragment; } default: { - goto s_n_llhttp__internal__n_error_79; + goto s_n_llhttp__internal__n_error_83; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_span_end_stub_query_3: s_n_llhttp__internal__n_span_end_stub_query_3: { @@ -3740,8 +3947,7 @@ static llparse_state_t llhttp__internal__run( } p++; goto s_n_llhttp__internal__n_url_fragment; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_url_query: s_n_llhttp__internal__n_url_query: { @@ -3788,11 +3994,10 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_span_end_stub_query_3; } default: { - goto s_n_llhttp__internal__n_error_80; + goto s_n_llhttp__internal__n_error_84; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_url_query_or_fragment: s_n_llhttp__internal__n_url_query_or_fragment: { @@ -3826,11 +4031,10 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_url_query; } default: { - goto s_n_llhttp__internal__n_error_81; + goto s_n_llhttp__internal__n_error_85; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_url_path: s_n_llhttp__internal__n_url_path: { @@ -3868,8 +4072,7 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_url_query_or_fragment; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_span_start_stub_path_2: s_n_llhttp__internal__n_span_start_stub_path_2: { @@ -3878,8 +4081,7 @@ static llparse_state_t llhttp__internal__run( } p++; goto s_n_llhttp__internal__n_url_path; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_span_start_stub_path: s_n_llhttp__internal__n_span_start_stub_path: { @@ -3888,8 +4090,7 @@ static llparse_state_t llhttp__internal__run( } p++; goto s_n_llhttp__internal__n_url_path; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_span_start_stub_path_1: s_n_llhttp__internal__n_span_start_stub_path_1: { @@ -3898,8 +4099,7 @@ static llparse_state_t llhttp__internal__run( } p++; goto s_n_llhttp__internal__n_url_path; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_url_server_with_at: s_n_llhttp__internal__n_url_server_with_at: { @@ -3951,14 +4151,13 @@ static llparse_state_t llhttp__internal__run( } case 8: { p++; - goto s_n_llhttp__internal__n_error_82; + goto s_n_llhttp__internal__n_error_86; } default: { - goto s_n_llhttp__internal__n_error_83; + goto s_n_llhttp__internal__n_error_87; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_url_server: s_n_llhttp__internal__n_url_server: { @@ -4013,11 +4212,10 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_url_server_with_at; } default: { - goto s_n_llhttp__internal__n_error_84; + goto s_n_llhttp__internal__n_error_88; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_url_schema_delim_1: s_n_llhttp__internal__n_url_schema_delim_1: { @@ -4030,11 +4228,10 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_url_server; } default: { - goto s_n_llhttp__internal__n_error_85; + goto s_n_llhttp__internal__n_error_89; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_url_schema_delim: s_n_llhttp__internal__n_url_schema_delim: { @@ -4067,11 +4264,10 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_url_schema_delim_1; } default: { - goto s_n_llhttp__internal__n_error_85; + goto s_n_llhttp__internal__n_error_89; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_span_end_stub_schema: s_n_llhttp__internal__n_span_end_stub_schema: { @@ -4080,8 +4276,7 @@ static llparse_state_t llhttp__internal__run( } p++; goto s_n_llhttp__internal__n_url_schema_delim; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_url_schema: s_n_llhttp__internal__n_url_schema: { @@ -4119,11 +4314,10 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_url_schema; } default: { - goto s_n_llhttp__internal__n_error_86; + goto s_n_llhttp__internal__n_error_90; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_url_start: s_n_llhttp__internal__n_url_start: { @@ -4160,11 +4354,10 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_url_schema; } default: { - goto s_n_llhttp__internal__n_error_87; + goto s_n_llhttp__internal__n_error_91; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_span_start_llhttp__on_url_1: s_n_llhttp__internal__n_span_start_llhttp__on_url_1: { @@ -4174,8 +4367,7 @@ static llparse_state_t llhttp__internal__run( state->_span_pos0 = (void*) p; state->_span_cb0 = llhttp__on_url; goto s_n_llhttp__internal__n_url_start; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_url_entry_normal: s_n_llhttp__internal__n_url_entry_normal: { @@ -4195,8 +4387,7 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_span_start_llhttp__on_url_1; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_span_start_llhttp__on_url: s_n_llhttp__internal__n_span_start_llhttp__on_url: { @@ -4206,8 +4397,7 @@ static llparse_state_t llhttp__internal__run( state->_span_pos0 = (void*) p; state->_span_cb0 = llhttp__on_url; goto s_n_llhttp__internal__n_url_server; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_url_entry_connect: s_n_llhttp__internal__n_url_entry_connect: { @@ -4227,8 +4417,7 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_span_start_llhttp__on_url; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_req_spaces_before_url: s_n_llhttp__internal__n_req_spaces_before_url: { @@ -4244,8 +4433,7 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_invoke_is_equal_method; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_req_first_space_before_url: s_n_llhttp__internal__n_req_first_space_before_url: { @@ -4258,11 +4446,10 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_req_spaces_before_url; } default: { - goto s_n_llhttp__internal__n_error_88; + goto s_n_llhttp__internal__n_error_92; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_invoke_llhttp__on_method_complete_1: s_n_llhttp__internal__n_invoke_llhttp__on_method_complete_1: { @@ -4270,12 +4457,11 @@ static llparse_state_t llhttp__internal__run( case 0: goto s_n_llhttp__internal__n_req_first_space_before_url; case 21: - goto s_n_llhttp__internal__n_pause_26; + goto s_n_llhttp__internal__n_pause_29; default: - goto s_n_llhttp__internal__n_error_107; + goto s_n_llhttp__internal__n_error_111; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_after_start_req_2: s_n_llhttp__internal__n_after_start_req_2: { @@ -4289,11 +4475,10 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_invoke_store_method_1; } default: { - goto s_n_llhttp__internal__n_error_108; + goto s_n_llhttp__internal__n_error_112; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_after_start_req_3: s_n_llhttp__internal__n_after_start_req_3: { @@ -4314,11 +4499,10 @@ static llparse_state_t llhttp__internal__run( return s_n_llhttp__internal__n_after_start_req_3; } case kMatchMismatch: { - goto s_n_llhttp__internal__n_error_108; + goto s_n_llhttp__internal__n_error_112; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_after_start_req_1: s_n_llhttp__internal__n_after_start_req_1: { @@ -4335,11 +4519,10 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_after_start_req_3; } default: { - goto s_n_llhttp__internal__n_error_108; + goto s_n_llhttp__internal__n_error_112; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_after_start_req_4: s_n_llhttp__internal__n_after_start_req_4: { @@ -4360,11 +4543,10 @@ static llparse_state_t llhttp__internal__run( return s_n_llhttp__internal__n_after_start_req_4; } case kMatchMismatch: { - goto s_n_llhttp__internal__n_error_108; + goto s_n_llhttp__internal__n_error_112; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_after_start_req_6: s_n_llhttp__internal__n_after_start_req_6: { @@ -4385,11 +4567,10 @@ static llparse_state_t llhttp__internal__run( return s_n_llhttp__internal__n_after_start_req_6; } case kMatchMismatch: { - goto s_n_llhttp__internal__n_error_108; + goto s_n_llhttp__internal__n_error_112; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_after_start_req_8: s_n_llhttp__internal__n_after_start_req_8: { @@ -4410,11 +4591,10 @@ static llparse_state_t llhttp__internal__run( return s_n_llhttp__internal__n_after_start_req_8; } case kMatchMismatch: { - goto s_n_llhttp__internal__n_error_108; + goto s_n_llhttp__internal__n_error_112; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_after_start_req_9: s_n_llhttp__internal__n_after_start_req_9: { @@ -4428,11 +4608,10 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_invoke_store_method_1; } default: { - goto s_n_llhttp__internal__n_error_108; + goto s_n_llhttp__internal__n_error_112; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_after_start_req_7: s_n_llhttp__internal__n_after_start_req_7: { @@ -4449,11 +4628,10 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_after_start_req_9; } default: { - goto s_n_llhttp__internal__n_error_108; + goto s_n_llhttp__internal__n_error_112; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_after_start_req_5: s_n_llhttp__internal__n_after_start_req_5: { @@ -4470,11 +4648,10 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_after_start_req_7; } default: { - goto s_n_llhttp__internal__n_error_108; + goto s_n_llhttp__internal__n_error_112; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_after_start_req_12: s_n_llhttp__internal__n_after_start_req_12: { @@ -4495,11 +4672,10 @@ static llparse_state_t llhttp__internal__run( return s_n_llhttp__internal__n_after_start_req_12; } case kMatchMismatch: { - goto s_n_llhttp__internal__n_error_108; + goto s_n_llhttp__internal__n_error_112; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_after_start_req_13: s_n_llhttp__internal__n_after_start_req_13: { @@ -4520,11 +4696,10 @@ static llparse_state_t llhttp__internal__run( return s_n_llhttp__internal__n_after_start_req_13; } case kMatchMismatch: { - goto s_n_llhttp__internal__n_error_108; + goto s_n_llhttp__internal__n_error_112; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_after_start_req_11: s_n_llhttp__internal__n_after_start_req_11: { @@ -4541,11 +4716,10 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_after_start_req_13; } default: { - goto s_n_llhttp__internal__n_error_108; + goto s_n_llhttp__internal__n_error_112; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_after_start_req_10: s_n_llhttp__internal__n_after_start_req_10: { @@ -4558,11 +4732,10 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_after_start_req_11; } default: { - goto s_n_llhttp__internal__n_error_108; + goto s_n_llhttp__internal__n_error_112; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_after_start_req_14: s_n_llhttp__internal__n_after_start_req_14: { @@ -4583,11 +4756,10 @@ static llparse_state_t llhttp__internal__run( return s_n_llhttp__internal__n_after_start_req_14; } case kMatchMismatch: { - goto s_n_llhttp__internal__n_error_108; + goto s_n_llhttp__internal__n_error_112; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_after_start_req_17: s_n_llhttp__internal__n_after_start_req_17: { @@ -4608,11 +4780,10 @@ static llparse_state_t llhttp__internal__run( return s_n_llhttp__internal__n_after_start_req_17; } case kMatchMismatch: { - goto s_n_llhttp__internal__n_error_108; + goto s_n_llhttp__internal__n_error_112; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_after_start_req_16: s_n_llhttp__internal__n_after_start_req_16: { @@ -4629,8 +4800,7 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_invoke_store_method_1; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_after_start_req_15: s_n_llhttp__internal__n_after_start_req_15: { @@ -4650,11 +4820,10 @@ static llparse_state_t llhttp__internal__run( return s_n_llhttp__internal__n_after_start_req_15; } case kMatchMismatch: { - goto s_n_llhttp__internal__n_error_108; + goto s_n_llhttp__internal__n_error_112; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_after_start_req_18: s_n_llhttp__internal__n_after_start_req_18: { @@ -4675,11 +4844,10 @@ static llparse_state_t llhttp__internal__run( return s_n_llhttp__internal__n_after_start_req_18; } case kMatchMismatch: { - goto s_n_llhttp__internal__n_error_108; + goto s_n_llhttp__internal__n_error_112; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_after_start_req_20: s_n_llhttp__internal__n_after_start_req_20: { @@ -4700,11 +4868,10 @@ static llparse_state_t llhttp__internal__run( return s_n_llhttp__internal__n_after_start_req_20; } case kMatchMismatch: { - goto s_n_llhttp__internal__n_error_108; + goto s_n_llhttp__internal__n_error_112; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_after_start_req_21: s_n_llhttp__internal__n_after_start_req_21: { @@ -4725,11 +4892,10 @@ static llparse_state_t llhttp__internal__run( return s_n_llhttp__internal__n_after_start_req_21; } case kMatchMismatch: { - goto s_n_llhttp__internal__n_error_108; + goto s_n_llhttp__internal__n_error_112; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_after_start_req_19: s_n_llhttp__internal__n_after_start_req_19: { @@ -4746,11 +4912,10 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_after_start_req_21; } default: { - goto s_n_llhttp__internal__n_error_108; + goto s_n_llhttp__internal__n_error_112; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_after_start_req_23: s_n_llhttp__internal__n_after_start_req_23: { @@ -4771,11 +4936,10 @@ static llparse_state_t llhttp__internal__run( return s_n_llhttp__internal__n_after_start_req_23; } case kMatchMismatch: { - goto s_n_llhttp__internal__n_error_108; + goto s_n_llhttp__internal__n_error_112; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_after_start_req_24: s_n_llhttp__internal__n_after_start_req_24: { @@ -4796,11 +4960,10 @@ static llparse_state_t llhttp__internal__run( return s_n_llhttp__internal__n_after_start_req_24; } case kMatchMismatch: { - goto s_n_llhttp__internal__n_error_108; + goto s_n_llhttp__internal__n_error_112; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_after_start_req_26: s_n_llhttp__internal__n_after_start_req_26: { @@ -4821,11 +4984,10 @@ static llparse_state_t llhttp__internal__run( return s_n_llhttp__internal__n_after_start_req_26; } case kMatchMismatch: { - goto s_n_llhttp__internal__n_error_108; + goto s_n_llhttp__internal__n_error_112; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_after_start_req_28: s_n_llhttp__internal__n_after_start_req_28: { @@ -4846,11 +5008,10 @@ static llparse_state_t llhttp__internal__run( return s_n_llhttp__internal__n_after_start_req_28; } case kMatchMismatch: { - goto s_n_llhttp__internal__n_error_108; + goto s_n_llhttp__internal__n_error_112; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_after_start_req_29: s_n_llhttp__internal__n_after_start_req_29: { @@ -4864,11 +5025,10 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_invoke_store_method_1; } default: { - goto s_n_llhttp__internal__n_error_108; + goto s_n_llhttp__internal__n_error_112; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_after_start_req_27: s_n_llhttp__internal__n_after_start_req_27: { @@ -4885,11 +5045,10 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_after_start_req_29; } default: { - goto s_n_llhttp__internal__n_error_108; + goto s_n_llhttp__internal__n_error_112; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_after_start_req_25: s_n_llhttp__internal__n_after_start_req_25: { @@ -4906,11 +5065,10 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_after_start_req_27; } default: { - goto s_n_llhttp__internal__n_error_108; + goto s_n_llhttp__internal__n_error_112; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_after_start_req_30: s_n_llhttp__internal__n_after_start_req_30: { @@ -4931,11 +5089,10 @@ static llparse_state_t llhttp__internal__run( return s_n_llhttp__internal__n_after_start_req_30; } case kMatchMismatch: { - goto s_n_llhttp__internal__n_error_108; + goto s_n_llhttp__internal__n_error_112; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_after_start_req_22: s_n_llhttp__internal__n_after_start_req_22: { @@ -4960,11 +5117,10 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_after_start_req_30; } default: { - goto s_n_llhttp__internal__n_error_108; + goto s_n_llhttp__internal__n_error_112; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_after_start_req_31: s_n_llhttp__internal__n_after_start_req_31: { @@ -4985,11 +5141,10 @@ static llparse_state_t llhttp__internal__run( return s_n_llhttp__internal__n_after_start_req_31; } case kMatchMismatch: { - goto s_n_llhttp__internal__n_error_108; + goto s_n_llhttp__internal__n_error_112; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_after_start_req_32: s_n_llhttp__internal__n_after_start_req_32: { @@ -5010,11 +5165,10 @@ static llparse_state_t llhttp__internal__run( return s_n_llhttp__internal__n_after_start_req_32; } case kMatchMismatch: { - goto s_n_llhttp__internal__n_error_108; + goto s_n_llhttp__internal__n_error_112; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_after_start_req_35: s_n_llhttp__internal__n_after_start_req_35: { @@ -5035,11 +5189,10 @@ static llparse_state_t llhttp__internal__run( return s_n_llhttp__internal__n_after_start_req_35; } case kMatchMismatch: { - goto s_n_llhttp__internal__n_error_108; + goto s_n_llhttp__internal__n_error_112; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_after_start_req_36: s_n_llhttp__internal__n_after_start_req_36: { @@ -5060,11 +5213,10 @@ static llparse_state_t llhttp__internal__run( return s_n_llhttp__internal__n_after_start_req_36; } case kMatchMismatch: { - goto s_n_llhttp__internal__n_error_108; + goto s_n_llhttp__internal__n_error_112; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_after_start_req_34: s_n_llhttp__internal__n_after_start_req_34: { @@ -5081,11 +5233,10 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_after_start_req_36; } default: { - goto s_n_llhttp__internal__n_error_108; + goto s_n_llhttp__internal__n_error_112; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_after_start_req_37: s_n_llhttp__internal__n_after_start_req_37: { @@ -5106,11 +5257,10 @@ static llparse_state_t llhttp__internal__run( return s_n_llhttp__internal__n_after_start_req_37; } case kMatchMismatch: { - goto s_n_llhttp__internal__n_error_108; + goto s_n_llhttp__internal__n_error_112; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_after_start_req_38: s_n_llhttp__internal__n_after_start_req_38: { @@ -5131,11 +5281,10 @@ static llparse_state_t llhttp__internal__run( return s_n_llhttp__internal__n_after_start_req_38; } case kMatchMismatch: { - goto s_n_llhttp__internal__n_error_108; + goto s_n_llhttp__internal__n_error_112; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_after_start_req_42: s_n_llhttp__internal__n_after_start_req_42: { @@ -5156,11 +5305,10 @@ static llparse_state_t llhttp__internal__run( return s_n_llhttp__internal__n_after_start_req_42; } case kMatchMismatch: { - goto s_n_llhttp__internal__n_error_108; + goto s_n_llhttp__internal__n_error_112; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_after_start_req_43: s_n_llhttp__internal__n_after_start_req_43: { @@ -5181,11 +5329,10 @@ static llparse_state_t llhttp__internal__run( return s_n_llhttp__internal__n_after_start_req_43; } case kMatchMismatch: { - goto s_n_llhttp__internal__n_error_108; + goto s_n_llhttp__internal__n_error_112; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_after_start_req_41: s_n_llhttp__internal__n_after_start_req_41: { @@ -5202,11 +5349,10 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_after_start_req_43; } default: { - goto s_n_llhttp__internal__n_error_108; + goto s_n_llhttp__internal__n_error_112; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_after_start_req_40: s_n_llhttp__internal__n_after_start_req_40: { @@ -5219,11 +5365,10 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_after_start_req_41; } default: { - goto s_n_llhttp__internal__n_error_108; + goto s_n_llhttp__internal__n_error_112; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_after_start_req_39: s_n_llhttp__internal__n_after_start_req_39: { @@ -5241,11 +5386,10 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_after_start_req_40; } default: { - goto s_n_llhttp__internal__n_error_108; + goto s_n_llhttp__internal__n_error_112; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_after_start_req_45: s_n_llhttp__internal__n_after_start_req_45: { @@ -5266,11 +5410,10 @@ static llparse_state_t llhttp__internal__run( return s_n_llhttp__internal__n_after_start_req_45; } case kMatchMismatch: { - goto s_n_llhttp__internal__n_error_108; + goto s_n_llhttp__internal__n_error_112; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_after_start_req_44: s_n_llhttp__internal__n_after_start_req_44: { @@ -5288,11 +5431,10 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_invoke_store_method_1; } default: { - goto s_n_llhttp__internal__n_error_108; + goto s_n_llhttp__internal__n_error_112; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_after_start_req_33: s_n_llhttp__internal__n_after_start_req_33: { @@ -5321,11 +5463,10 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_after_start_req_44; } default: { - goto s_n_llhttp__internal__n_error_108; + goto s_n_llhttp__internal__n_error_112; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_after_start_req_46: s_n_llhttp__internal__n_after_start_req_46: { @@ -5346,11 +5487,10 @@ static llparse_state_t llhttp__internal__run( return s_n_llhttp__internal__n_after_start_req_46; } case kMatchMismatch: { - goto s_n_llhttp__internal__n_error_108; + goto s_n_llhttp__internal__n_error_112; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_after_start_req_49: s_n_llhttp__internal__n_after_start_req_49: { @@ -5371,11 +5511,10 @@ static llparse_state_t llhttp__internal__run( return s_n_llhttp__internal__n_after_start_req_49; } case kMatchMismatch: { - goto s_n_llhttp__internal__n_error_108; + goto s_n_llhttp__internal__n_error_112; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_after_start_req_50: s_n_llhttp__internal__n_after_start_req_50: { @@ -5396,11 +5535,10 @@ static llparse_state_t llhttp__internal__run( return s_n_llhttp__internal__n_after_start_req_50; } case kMatchMismatch: { - goto s_n_llhttp__internal__n_error_108; + goto s_n_llhttp__internal__n_error_112; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_after_start_req_51: s_n_llhttp__internal__n_after_start_req_51: { @@ -5421,11 +5559,10 @@ static llparse_state_t llhttp__internal__run( return s_n_llhttp__internal__n_after_start_req_51; } case kMatchMismatch: { - goto s_n_llhttp__internal__n_error_108; + goto s_n_llhttp__internal__n_error_112; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_after_start_req_52: s_n_llhttp__internal__n_after_start_req_52: { @@ -5446,11 +5583,10 @@ static llparse_state_t llhttp__internal__run( return s_n_llhttp__internal__n_after_start_req_52; } case kMatchMismatch: { - goto s_n_llhttp__internal__n_error_108; + goto s_n_llhttp__internal__n_error_112; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_after_start_req_48: s_n_llhttp__internal__n_after_start_req_48: { @@ -5475,11 +5611,10 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_after_start_req_52; } default: { - goto s_n_llhttp__internal__n_error_108; + goto s_n_llhttp__internal__n_error_112; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_after_start_req_47: s_n_llhttp__internal__n_after_start_req_47: { @@ -5492,11 +5627,10 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_after_start_req_48; } default: { - goto s_n_llhttp__internal__n_error_108; + goto s_n_llhttp__internal__n_error_112; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_after_start_req_55: s_n_llhttp__internal__n_after_start_req_55: { @@ -5517,11 +5651,10 @@ static llparse_state_t llhttp__internal__run( return s_n_llhttp__internal__n_after_start_req_55; } case kMatchMismatch: { - goto s_n_llhttp__internal__n_error_108; + goto s_n_llhttp__internal__n_error_112; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_after_start_req_57: s_n_llhttp__internal__n_after_start_req_57: { @@ -5535,11 +5668,10 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_invoke_store_method_1; } default: { - goto s_n_llhttp__internal__n_error_108; + goto s_n_llhttp__internal__n_error_112; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_after_start_req_58: s_n_llhttp__internal__n_after_start_req_58: { @@ -5560,11 +5692,10 @@ static llparse_state_t llhttp__internal__run( return s_n_llhttp__internal__n_after_start_req_58; } case kMatchMismatch: { - goto s_n_llhttp__internal__n_error_108; + goto s_n_llhttp__internal__n_error_112; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_after_start_req_56: s_n_llhttp__internal__n_after_start_req_56: { @@ -5581,11 +5712,10 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_after_start_req_58; } default: { - goto s_n_llhttp__internal__n_error_108; + goto s_n_llhttp__internal__n_error_112; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_after_start_req_54: s_n_llhttp__internal__n_after_start_req_54: { @@ -5602,11 +5732,10 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_after_start_req_56; } default: { - goto s_n_llhttp__internal__n_error_108; + goto s_n_llhttp__internal__n_error_112; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_after_start_req_59: s_n_llhttp__internal__n_after_start_req_59: { @@ -5627,11 +5756,10 @@ static llparse_state_t llhttp__internal__run( return s_n_llhttp__internal__n_after_start_req_59; } case kMatchMismatch: { - goto s_n_llhttp__internal__n_error_108; + goto s_n_llhttp__internal__n_error_112; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_after_start_req_60: s_n_llhttp__internal__n_after_start_req_60: { @@ -5652,11 +5780,10 @@ static llparse_state_t llhttp__internal__run( return s_n_llhttp__internal__n_after_start_req_60; } case kMatchMismatch: { - goto s_n_llhttp__internal__n_error_108; + goto s_n_llhttp__internal__n_error_112; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_after_start_req_53: s_n_llhttp__internal__n_after_start_req_53: { @@ -5677,11 +5804,10 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_after_start_req_60; } default: { - goto s_n_llhttp__internal__n_error_108; + goto s_n_llhttp__internal__n_error_112; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_after_start_req_62: s_n_llhttp__internal__n_after_start_req_62: { @@ -5702,11 +5828,10 @@ static llparse_state_t llhttp__internal__run( return s_n_llhttp__internal__n_after_start_req_62; } case kMatchMismatch: { - goto s_n_llhttp__internal__n_error_108; + goto s_n_llhttp__internal__n_error_112; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_after_start_req_63: s_n_llhttp__internal__n_after_start_req_63: { @@ -5727,11 +5852,10 @@ static llparse_state_t llhttp__internal__run( return s_n_llhttp__internal__n_after_start_req_63; } case kMatchMismatch: { - goto s_n_llhttp__internal__n_error_108; + goto s_n_llhttp__internal__n_error_112; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_after_start_req_61: s_n_llhttp__internal__n_after_start_req_61: { @@ -5748,11 +5872,10 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_after_start_req_63; } default: { - goto s_n_llhttp__internal__n_error_108; + goto s_n_llhttp__internal__n_error_112; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_after_start_req_66: s_n_llhttp__internal__n_after_start_req_66: { @@ -5773,11 +5896,10 @@ static llparse_state_t llhttp__internal__run( return s_n_llhttp__internal__n_after_start_req_66; } case kMatchMismatch: { - goto s_n_llhttp__internal__n_error_108; + goto s_n_llhttp__internal__n_error_112; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_after_start_req_68: s_n_llhttp__internal__n_after_start_req_68: { @@ -5798,11 +5920,10 @@ static llparse_state_t llhttp__internal__run( return s_n_llhttp__internal__n_after_start_req_68; } case kMatchMismatch: { - goto s_n_llhttp__internal__n_error_108; + goto s_n_llhttp__internal__n_error_112; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_after_start_req_69: s_n_llhttp__internal__n_after_start_req_69: { @@ -5823,11 +5944,10 @@ static llparse_state_t llhttp__internal__run( return s_n_llhttp__internal__n_after_start_req_69; } case kMatchMismatch: { - goto s_n_llhttp__internal__n_error_108; + goto s_n_llhttp__internal__n_error_112; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_after_start_req_67: s_n_llhttp__internal__n_after_start_req_67: { @@ -5844,11 +5964,10 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_after_start_req_69; } default: { - goto s_n_llhttp__internal__n_error_108; + goto s_n_llhttp__internal__n_error_112; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_after_start_req_70: s_n_llhttp__internal__n_after_start_req_70: { @@ -5869,11 +5988,10 @@ static llparse_state_t llhttp__internal__run( return s_n_llhttp__internal__n_after_start_req_70; } case kMatchMismatch: { - goto s_n_llhttp__internal__n_error_108; + goto s_n_llhttp__internal__n_error_112; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_after_start_req_65: s_n_llhttp__internal__n_after_start_req_65: { @@ -5894,11 +6012,10 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_after_start_req_70; } default: { - goto s_n_llhttp__internal__n_error_108; + goto s_n_llhttp__internal__n_error_112; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_after_start_req_64: s_n_llhttp__internal__n_after_start_req_64: { @@ -5911,11 +6028,10 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_after_start_req_65; } default: { - goto s_n_llhttp__internal__n_error_108; + goto s_n_llhttp__internal__n_error_112; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_after_start_req: s_n_llhttp__internal__n_after_start_req: { @@ -5992,11 +6108,10 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_after_start_req_64; } default: { - goto s_n_llhttp__internal__n_error_108; + goto s_n_llhttp__internal__n_error_112; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_span_start_llhttp__on_method_1: s_n_llhttp__internal__n_span_start_llhttp__on_method_1: { @@ -6006,8 +6121,7 @@ static llparse_state_t llhttp__internal__run( state->_span_pos0 = (void*) p; state->_span_cb0 = llhttp__on_method; goto s_n_llhttp__internal__n_after_start_req; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_res_line_almost_done: s_n_llhttp__internal__n_res_line_almost_done: { @@ -6027,8 +6141,7 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_invoke_test_lenient_flags_29; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_invoke_test_lenient_flags_30: s_n_llhttp__internal__n_invoke_test_lenient_flags_30: { @@ -6036,10 +6149,9 @@ static llparse_state_t llhttp__internal__run( case 1: goto s_n_llhttp__internal__n_invoke_llhttp__on_status_complete; default: - goto s_n_llhttp__internal__n_error_94; + goto s_n_llhttp__internal__n_error_98; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_res_status: s_n_llhttp__internal__n_res_status: { @@ -6058,8 +6170,7 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_res_status; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_span_start_llhttp__on_status: s_n_llhttp__internal__n_span_start_llhttp__on_status: { @@ -6069,8 +6180,7 @@ static llparse_state_t llhttp__internal__run( state->_span_pos0 = (void*) p; state->_span_cb0 = llhttp__on_status; goto s_n_llhttp__internal__n_res_status; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_res_status_code_otherwise: s_n_llhttp__internal__n_res_status_code_otherwise: { @@ -6091,11 +6201,10 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_span_start_llhttp__on_status; } default: { - goto s_n_llhttp__internal__n_error_95; + goto s_n_llhttp__internal__n_error_99; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_res_status_code_digit_3: s_n_llhttp__internal__n_res_status_code_digit_3: { @@ -6154,11 +6263,10 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_invoke_mul_add_status_code_2; } default: { - goto s_n_llhttp__internal__n_error_97; + goto s_n_llhttp__internal__n_error_101; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_res_status_code_digit_2: s_n_llhttp__internal__n_res_status_code_digit_2: { @@ -6217,11 +6325,10 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_invoke_mul_add_status_code_1; } default: { - goto s_n_llhttp__internal__n_error_99; + goto s_n_llhttp__internal__n_error_103; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_res_status_code_digit_1: s_n_llhttp__internal__n_res_status_code_digit_1: { @@ -6280,11 +6387,10 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_invoke_mul_add_status_code; } default: { - goto s_n_llhttp__internal__n_error_101; + goto s_n_llhttp__internal__n_error_105; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_res_after_version: s_n_llhttp__internal__n_res_after_version: { @@ -6297,11 +6403,10 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_invoke_update_status_code; } default: { - goto s_n_llhttp__internal__n_error_102; + goto s_n_llhttp__internal__n_error_106; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_invoke_llhttp__on_version_complete_1: s_n_llhttp__internal__n_invoke_llhttp__on_version_complete_1: { @@ -6309,32 +6414,29 @@ static llparse_state_t llhttp__internal__run( case 0: goto s_n_llhttp__internal__n_res_after_version; case 21: - goto s_n_llhttp__internal__n_pause_25; + goto s_n_llhttp__internal__n_pause_28; default: - goto s_n_llhttp__internal__n_error_90; + goto s_n_llhttp__internal__n_error_94; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } - case s_n_llhttp__internal__n_error_89: - s_n_llhttp__internal__n_error_89: { + case s_n_llhttp__internal__n_error_93: + s_n_llhttp__internal__n_error_93: { state->error = 0x9; state->reason = "Invalid HTTP version"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } - case s_n_llhttp__internal__n_error_103: - s_n_llhttp__internal__n_error_103: { + case s_n_llhttp__internal__n_error_107: + s_n_llhttp__internal__n_error_107: { state->error = 0x9; state->reason = "Invalid minor version"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_res_http_minor: s_n_llhttp__internal__n_res_http_minor: { @@ -6396,18 +6498,16 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_span_end_llhttp__on_version_7; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } - case s_n_llhttp__internal__n_error_104: - s_n_llhttp__internal__n_error_104: { + case s_n_llhttp__internal__n_error_108: + s_n_llhttp__internal__n_error_108: { state->error = 0x9; state->reason = "Expected dot"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_res_http_dot: s_n_llhttp__internal__n_res_http_dot: { @@ -6423,18 +6523,16 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_span_end_llhttp__on_version_8; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } - case s_n_llhttp__internal__n_error_105: - s_n_llhttp__internal__n_error_105: { + case s_n_llhttp__internal__n_error_109: + s_n_llhttp__internal__n_error_109: { state->error = 0x9; state->reason = "Invalid major version"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_res_http_major: s_n_llhttp__internal__n_res_http_major: { @@ -6496,8 +6594,7 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_span_end_llhttp__on_version_9; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_span_start_llhttp__on_version_1: s_n_llhttp__internal__n_span_start_llhttp__on_version_1: { @@ -6507,32 +6604,147 @@ static llparse_state_t llhttp__internal__run( state->_span_pos0 = (void*) p; state->_span_cb0 = llhttp__on_version; goto s_n_llhttp__internal__n_res_http_major; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } - case s_n_llhttp__internal__n_start_res: - s_n_llhttp__internal__n_start_res: { + case s_n_llhttp__internal__n_res_after_protocol: + s_n_llhttp__internal__n_res_after_protocol: { + if (p == endp) { + return s_n_llhttp__internal__n_res_after_protocol; + } + switch (*p) { + case '/': { + p++; + goto s_n_llhttp__internal__n_span_start_llhttp__on_version_1; + } + default: { + goto s_n_llhttp__internal__n_error_114; + } + } + UNREACHABLE; + } + case s_n_llhttp__internal__n_invoke_llhttp__on_protocol_complete_3: + s_n_llhttp__internal__n_invoke_llhttp__on_protocol_complete_3: { + switch (llhttp__on_protocol_complete(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_res_after_protocol; + case 21: + goto s_n_llhttp__internal__n_pause_30; + default: + goto s_n_llhttp__internal__n_error_113; + } + UNREACHABLE; + } + case s_n_llhttp__internal__n_error_115: + s_n_llhttp__internal__n_error_115: { + state->error = 0x8; + state->reason = "Expected HTTP/, RTSP/ or ICE/"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + UNREACHABLE; + } + case s_n_llhttp__internal__n_res_after_start_1: + s_n_llhttp__internal__n_res_after_start_1: { llparse_match_t match_seq; if (p == endp) { - return s_n_llhttp__internal__n_start_res; + return s_n_llhttp__internal__n_res_after_start_1; } - match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob58, 5); + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob58, 3); p = match_seq.current; switch (match_seq.status) { case kMatchComplete: { p++; - goto s_n_llhttp__internal__n_span_start_llhttp__on_version_1; + goto s_n_llhttp__internal__n_span_end_llhttp__on_protocol_4; + } + case kMatchPause: { + return s_n_llhttp__internal__n_res_after_start_1; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_protocol_5; + } + } + UNREACHABLE; + } + case s_n_llhttp__internal__n_res_after_start_2: + s_n_llhttp__internal__n_res_after_start_2: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_res_after_start_2; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob59, 2); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + goto s_n_llhttp__internal__n_span_end_llhttp__on_protocol_4; + } + case kMatchPause: { + return s_n_llhttp__internal__n_res_after_start_2; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_protocol_5; + } + } + UNREACHABLE; + } + case s_n_llhttp__internal__n_res_after_start_3: + s_n_llhttp__internal__n_res_after_start_3: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_res_after_start_3; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob60, 3); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + goto s_n_llhttp__internal__n_span_end_llhttp__on_protocol_4; } case kMatchPause: { - return s_n_llhttp__internal__n_start_res; + return s_n_llhttp__internal__n_res_after_start_3; } case kMatchMismatch: { - goto s_n_llhttp__internal__n_error_109; + goto s_n_llhttp__internal__n_span_end_llhttp__on_protocol_5; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; + } + case s_n_llhttp__internal__n_res_after_start: + s_n_llhttp__internal__n_res_after_start: { + if (p == endp) { + return s_n_llhttp__internal__n_res_after_start; + } + switch (*p) { + case 'H': { + p++; + goto s_n_llhttp__internal__n_res_after_start_1; + } + case 'I': { + p++; + goto s_n_llhttp__internal__n_res_after_start_2; + } + case 'R': { + p++; + goto s_n_llhttp__internal__n_res_after_start_3; + } + default: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_protocol_5; + } + } + UNREACHABLE; + } + case s_n_llhttp__internal__n_span_start_llhttp__on_protocol_1: + s_n_llhttp__internal__n_span_start_llhttp__on_protocol_1: { + if (p == endp) { + return s_n_llhttp__internal__n_span_start_llhttp__on_protocol_1; + } + state->_span_pos0 = (void*) p; + state->_span_cb0 = llhttp__on_protocol; + goto s_n_llhttp__internal__n_res_after_start; + UNREACHABLE; } case s_n_llhttp__internal__n_invoke_llhttp__on_method_complete: s_n_llhttp__internal__n_invoke_llhttp__on_method_complete: { @@ -6540,12 +6752,11 @@ static llparse_state_t llhttp__internal__run( case 0: goto s_n_llhttp__internal__n_req_first_space_before_url; case 21: - goto s_n_llhttp__internal__n_pause_23; + goto s_n_llhttp__internal__n_pause_26; default: goto s_n_llhttp__internal__n_error_1; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_req_or_res_method_2: s_n_llhttp__internal__n_req_or_res_method_2: { @@ -6554,7 +6765,7 @@ static llparse_state_t llhttp__internal__run( if (p == endp) { return s_n_llhttp__internal__n_req_or_res_method_2; } - match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob59, 2); + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob61, 2); p = match_seq.current; switch (match_seq.status) { case kMatchComplete: { @@ -6566,11 +6777,10 @@ static llparse_state_t llhttp__internal__run( return s_n_llhttp__internal__n_req_or_res_method_2; } case kMatchMismatch: { - goto s_n_llhttp__internal__n_error_106; + goto s_n_llhttp__internal__n_error_110; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_invoke_update_type_1: s_n_llhttp__internal__n_invoke_update_type_1: { @@ -6578,8 +6788,7 @@ static llparse_state_t llhttp__internal__run( default: goto s_n_llhttp__internal__n_span_start_llhttp__on_version_1; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_req_or_res_method_3: s_n_llhttp__internal__n_req_or_res_method_3: { @@ -6588,7 +6797,7 @@ static llparse_state_t llhttp__internal__run( if (p == endp) { return s_n_llhttp__internal__n_req_or_res_method_3; } - match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob60, 3); + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob62, 3); p = match_seq.current; switch (match_seq.status) { case kMatchComplete: { @@ -6599,11 +6808,10 @@ static llparse_state_t llhttp__internal__run( return s_n_llhttp__internal__n_req_or_res_method_3; } case kMatchMismatch: { - goto s_n_llhttp__internal__n_error_106; + goto s_n_llhttp__internal__n_error_110; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_req_or_res_method_1: s_n_llhttp__internal__n_req_or_res_method_1: { @@ -6620,11 +6828,10 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_req_or_res_method_3; } default: { - goto s_n_llhttp__internal__n_error_106; + goto s_n_llhttp__internal__n_error_110; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_req_or_res_method: s_n_llhttp__internal__n_req_or_res_method: { @@ -6637,11 +6844,10 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_req_or_res_method_1; } default: { - goto s_n_llhttp__internal__n_error_106; + goto s_n_llhttp__internal__n_error_110; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_span_start_llhttp__on_method: s_n_llhttp__internal__n_span_start_llhttp__on_method: { @@ -6651,8 +6857,7 @@ static llparse_state_t llhttp__internal__run( state->_span_pos0 = (void*) p; state->_span_cb0 = llhttp__on_method; goto s_n_llhttp__internal__n_req_or_res_method; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_start_req_or_res: s_n_llhttp__internal__n_start_req_or_res: { @@ -6667,8 +6872,7 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_invoke_update_type_2; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_invoke_load_type: s_n_llhttp__internal__n_invoke_load_type: { @@ -6676,12 +6880,11 @@ static llparse_state_t llhttp__internal__run( case 1: goto s_n_llhttp__internal__n_span_start_llhttp__on_method_1; case 2: - goto s_n_llhttp__internal__n_start_res; + goto s_n_llhttp__internal__n_span_start_llhttp__on_protocol_1; default: goto s_n_llhttp__internal__n_start_req_or_res; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_invoke_update_finish: s_n_llhttp__internal__n_invoke_update_finish: { @@ -6689,8 +6892,7 @@ static llparse_state_t llhttp__internal__run( default: goto s_n_llhttp__internal__n_invoke_llhttp__on_message_begin; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } case s_n_llhttp__internal__n_start: s_n_llhttp__internal__n_start: { @@ -6710,12 +6912,10 @@ static llparse_state_t llhttp__internal__run( goto s_n_llhttp__internal__n_invoke_load_initial_message_completed; } } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } default: - /* UNREACHABLE */ - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_error_2: { state->error = 0x7; @@ -6723,32 +6923,28 @@ static llparse_state_t llhttp__internal__run( state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_update_finish_2: { switch (llhttp__internal__c_update_finish_1(state, p, endp)) { default: goto s_n_llhttp__internal__n_start; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_update_initial_message_completed: { switch (llhttp__internal__c_update_initial_message_completed(state, p, endp)) { default: goto s_n_llhttp__internal__n_invoke_update_finish_2; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_update_content_length: { switch (llhttp__internal__c_update_content_length(state, p, endp)) { default: goto s_n_llhttp__internal__n_invoke_update_initial_message_completed; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_error_8: { state->error = 0x5; @@ -6756,8 +6952,7 @@ static llparse_state_t llhttp__internal__run( state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_test_lenient_flags_3: { switch (llhttp__internal__c_test_lenient_flags_3(state, p, endp)) { @@ -6766,8 +6961,7 @@ static llparse_state_t llhttp__internal__run( default: goto s_n_llhttp__internal__n_error_8; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_test_lenient_flags_2: { switch (llhttp__internal__c_test_lenient_flags_2(state, p, endp)) { @@ -6776,16 +6970,14 @@ static llparse_state_t llhttp__internal__run( default: goto s_n_llhttp__internal__n_closed; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_update_finish_1: { switch (llhttp__internal__c_update_finish_1(state, p, endp)) { default: goto s_n_llhttp__internal__n_invoke_test_lenient_flags_2; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_pause_13: { state->error = 0x15; @@ -6793,8 +6985,7 @@ static llparse_state_t llhttp__internal__run( state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_is_equal_upgrade; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_error_38: { state->error = 0x12; @@ -6802,8 +6993,7 @@ static llparse_state_t llhttp__internal__run( state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_pause_15: { state->error = 0x15; @@ -6811,8 +7001,7 @@ static llparse_state_t llhttp__internal__run( state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__on_message_complete_2; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_error_40: { state->error = 0x14; @@ -6820,8 +7009,7 @@ static llparse_state_t llhttp__internal__run( state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_llhttp__on_chunk_complete_1: { switch (llhttp__on_chunk_complete(state, p, endp)) { @@ -6832,8 +7020,7 @@ static llparse_state_t llhttp__internal__run( default: goto s_n_llhttp__internal__n_error_40; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_pause_2: { state->error = 0x15; @@ -6841,8 +7028,7 @@ static llparse_state_t llhttp__internal__run( state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_pause_1; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_error_9: { state->error = 0x12; @@ -6850,8 +7036,7 @@ static llparse_state_t llhttp__internal__run( state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_llhttp__on_message_complete_1: { switch (llhttp__on_message_complete(state, p, endp)) { @@ -6862,8 +7047,7 @@ static llparse_state_t llhttp__internal__run( default: goto s_n_llhttp__internal__n_error_9; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_error_36: { state->error = 0xc; @@ -6871,8 +7055,7 @@ static llparse_state_t llhttp__internal__run( state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_error_10: { state->error = 0xc; @@ -6880,8 +7063,7 @@ static llparse_state_t llhttp__internal__run( state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_test_lenient_flags_4: { switch (llhttp__internal__c_test_lenient_flags_4(state, p, endp)) { @@ -6890,8 +7072,7 @@ static llparse_state_t llhttp__internal__run( default: goto s_n_llhttp__internal__n_error_10; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_pause_3: { state->error = 0x15; @@ -6899,8 +7080,7 @@ static llparse_state_t llhttp__internal__run( state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_update_content_length_1; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_error_14: { state->error = 0x14; @@ -6908,8 +7088,7 @@ static llparse_state_t llhttp__internal__run( state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_llhttp__on_chunk_complete: { switch (llhttp__on_chunk_complete(state, p, endp)) { @@ -6920,8 +7099,7 @@ static llparse_state_t llhttp__internal__run( default: goto s_n_llhttp__internal__n_error_14; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_error_13: { state->error = 0x19; @@ -6929,8 +7107,7 @@ static llparse_state_t llhttp__internal__run( state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_test_lenient_flags_6: { switch (llhttp__internal__c_test_lenient_flags_1(state, p, endp)) { @@ -6939,8 +7116,7 @@ static llparse_state_t llhttp__internal__run( default: goto s_n_llhttp__internal__n_error_13; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_error_15: { state->error = 0x2; @@ -6948,8 +7124,7 @@ static llparse_state_t llhttp__internal__run( state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_test_lenient_flags_7: { switch (llhttp__internal__c_test_lenient_flags_7(state, p, endp)) { @@ -6958,8 +7133,7 @@ static llparse_state_t llhttp__internal__run( default: goto s_n_llhttp__internal__n_error_15; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_span_end_llhttp__on_body: { const unsigned char* start; @@ -6975,16 +7149,14 @@ static llparse_state_t llhttp__internal__run( return s_error; } goto s_n_llhttp__internal__n_chunk_data_almost_done; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_or_flags: { switch (llhttp__internal__c_or_flags(state, p, endp)) { default: goto s_n_llhttp__internal__n_header_field_start; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_pause_4: { state->error = 0x15; @@ -6992,8 +7164,7 @@ static llparse_state_t llhttp__internal__run( state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_is_equal_content_length; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_error_12: { state->error = 0x13; @@ -7001,8 +7172,7 @@ static llparse_state_t llhttp__internal__run( state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_llhttp__on_chunk_header: { switch (llhttp__on_chunk_header(state, p, endp)) { @@ -7013,8 +7183,7 @@ static llparse_state_t llhttp__internal__run( default: goto s_n_llhttp__internal__n_error_12; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_error_16: { state->error = 0x2; @@ -7022,8 +7191,7 @@ static llparse_state_t llhttp__internal__run( state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_test_lenient_flags_8: { switch (llhttp__internal__c_test_lenient_flags_8(state, p, endp)) { @@ -7032,8 +7200,7 @@ static llparse_state_t llhttp__internal__run( default: goto s_n_llhttp__internal__n_error_16; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_error_11: { state->error = 0x19; @@ -7041,8 +7208,7 @@ static llparse_state_t llhttp__internal__run( state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_test_lenient_flags_5: { switch (llhttp__internal__c_test_lenient_flags_1(state, p, endp)) { @@ -7051,8 +7217,7 @@ static llparse_state_t llhttp__internal__run( default: goto s_n_llhttp__internal__n_error_11; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_error_17: { state->error = 0x2; @@ -7060,8 +7225,7 @@ static llparse_state_t llhttp__internal__run( state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_error_18: { state->error = 0x2; @@ -7069,8 +7233,7 @@ static llparse_state_t llhttp__internal__run( state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_error_20: { state->error = 0x19; @@ -7078,8 +7241,7 @@ static llparse_state_t llhttp__internal__run( state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_pause_5: { state->error = 0x15; @@ -7087,8 +7249,7 @@ static llparse_state_t llhttp__internal__run( state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_test_lenient_flags_9; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_error_19: { state->error = 0x22; @@ -7096,8 +7257,7 @@ static llparse_state_t llhttp__internal__run( state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_span_end_llhttp__on_chunk_extension_name: { const unsigned char* start; @@ -7113,8 +7273,7 @@ static llparse_state_t llhttp__internal__run( return s_error; } goto s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_name_complete; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_pause_6: { state->error = 0x15; @@ -7122,8 +7281,7 @@ static llparse_state_t llhttp__internal__run( state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_chunk_size_almost_done; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_error_21: { state->error = 0x22; @@ -7131,8 +7289,7 @@ static llparse_state_t llhttp__internal__run( state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_span_end_llhttp__on_chunk_extension_name_1: { const unsigned char* start; @@ -7149,8 +7306,7 @@ static llparse_state_t llhttp__internal__run( } p++; goto s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_name_complete_1; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_pause_7: { state->error = 0x15; @@ -7158,8 +7314,7 @@ static llparse_state_t llhttp__internal__run( state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_chunk_extensions; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_error_22: { state->error = 0x22; @@ -7167,8 +7322,7 @@ static llparse_state_t llhttp__internal__run( state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_span_end_llhttp__on_chunk_extension_name_2: { const unsigned char* start; @@ -7185,8 +7339,7 @@ static llparse_state_t llhttp__internal__run( } p++; goto s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_name_complete_2; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_error_25: { state->error = 0x19; @@ -7194,8 +7347,7 @@ static llparse_state_t llhttp__internal__run( state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_pause_8: { state->error = 0x15; @@ -7203,8 +7355,7 @@ static llparse_state_t llhttp__internal__run( state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_test_lenient_flags_10; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_error_24: { state->error = 0x23; @@ -7212,8 +7363,7 @@ static llparse_state_t llhttp__internal__run( state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_span_end_llhttp__on_chunk_extension_value: { const unsigned char* start; @@ -7229,8 +7379,7 @@ static llparse_state_t llhttp__internal__run( return s_error; } goto s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_value_complete; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_pause_9: { state->error = 0x15; @@ -7238,8 +7387,7 @@ static llparse_state_t llhttp__internal__run( state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_chunk_size_almost_done; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_error_26: { state->error = 0x23; @@ -7247,8 +7395,7 @@ static llparse_state_t llhttp__internal__run( state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_span_end_llhttp__on_chunk_extension_value_1: { const unsigned char* start; @@ -7265,8 +7412,7 @@ static llparse_state_t llhttp__internal__run( } p++; goto s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_value_complete_1; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_error_28: { state->error = 0x19; @@ -7274,8 +7420,7 @@ static llparse_state_t llhttp__internal__run( state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_test_lenient_flags_11: { switch (llhttp__internal__c_test_lenient_flags_1(state, p, endp)) { @@ -7284,8 +7429,7 @@ static llparse_state_t llhttp__internal__run( default: goto s_n_llhttp__internal__n_error_28; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_error_29: { state->error = 0x2; @@ -7293,8 +7437,7 @@ static llparse_state_t llhttp__internal__run( state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_pause_10: { state->error = 0x15; @@ -7302,8 +7445,7 @@ static llparse_state_t llhttp__internal__run( state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_chunk_extension_quoted_value_done; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_error_27: { state->error = 0x23; @@ -7311,8 +7453,7 @@ static llparse_state_t llhttp__internal__run( state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_span_end_llhttp__on_chunk_extension_value_2: { const unsigned char* start; @@ -7328,8 +7469,7 @@ static llparse_state_t llhttp__internal__run( return s_error; } goto s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_value_complete_2; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_span_end_llhttp__on_chunk_extension_value_3: { const unsigned char* start; @@ -7346,8 +7486,7 @@ static llparse_state_t llhttp__internal__run( } p++; goto s_n_llhttp__internal__n_error_30; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_span_end_llhttp__on_chunk_extension_value_4: { const unsigned char* start; @@ -7364,8 +7503,7 @@ static llparse_state_t llhttp__internal__run( } p++; goto s_n_llhttp__internal__n_error_31; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_pause_11: { state->error = 0x15; @@ -7373,8 +7511,7 @@ static llparse_state_t llhttp__internal__run( state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_chunk_extensions; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_error_32: { state->error = 0x23; @@ -7382,8 +7519,7 @@ static llparse_state_t llhttp__internal__run( state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_span_end_llhttp__on_chunk_extension_value_5: { const unsigned char* start; @@ -7400,8 +7536,7 @@ static llparse_state_t llhttp__internal__run( } p++; goto s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_value_complete_3; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_span_end_llhttp__on_chunk_extension_value_6: { const unsigned char* start; @@ -7418,8 +7553,7 @@ static llparse_state_t llhttp__internal__run( } p++; goto s_n_llhttp__internal__n_error_33; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_pause_12: { state->error = 0x15; @@ -7427,8 +7561,7 @@ static llparse_state_t llhttp__internal__run( state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_chunk_extension_value; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_error_23: { state->error = 0x22; @@ -7436,8 +7569,7 @@ static llparse_state_t llhttp__internal__run( state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_name_complete_3: { switch (llhttp__on_chunk_extension_name_complete(state, p, endp)) { @@ -7448,8 +7580,7 @@ static llparse_state_t llhttp__internal__run( default: goto s_n_llhttp__internal__n_error_23; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_span_end_llhttp__on_chunk_extension_name_3: { const unsigned char* start; @@ -7466,8 +7597,7 @@ static llparse_state_t llhttp__internal__run( } p++; goto s_n_llhttp__internal__n_span_start_llhttp__on_chunk_extension_value; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_span_end_llhttp__on_chunk_extension_name_4: { const unsigned char* start; @@ -7484,8 +7614,7 @@ static llparse_state_t llhttp__internal__run( } p++; goto s_n_llhttp__internal__n_error_34; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_error_35: { state->error = 0xc; @@ -7493,8 +7622,7 @@ static llparse_state_t llhttp__internal__run( state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_mul_add_content_length: { switch (llhttp__internal__c_mul_add_content_length(state, p, endp, match)) { @@ -7503,8 +7631,7 @@ static llparse_state_t llhttp__internal__run( default: goto s_n_llhttp__internal__n_chunk_size; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_error_37: { state->error = 0xc; @@ -7512,8 +7639,7 @@ static llparse_state_t llhttp__internal__run( state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_span_end_llhttp__on_body_1: { const unsigned char* start; @@ -7529,16 +7655,14 @@ static llparse_state_t llhttp__internal__run( return s_error; } goto s_n_llhttp__internal__n_invoke_llhttp__on_message_complete_2; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_update_finish_3: { switch (llhttp__internal__c_update_finish_3(state, p, endp)) { default: goto s_n_llhttp__internal__n_span_start_llhttp__on_body_2; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_error_39: { state->error = 0xf; @@ -7546,8 +7670,7 @@ static llparse_state_t llhttp__internal__run( state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_pause: { state->error = 0x15; @@ -7555,8 +7678,7 @@ static llparse_state_t llhttp__internal__run( state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__after_message_complete; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_error_7: { state->error = 0x12; @@ -7564,8 +7686,7 @@ static llparse_state_t llhttp__internal__run( state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_llhttp__on_message_complete: { switch (llhttp__on_message_complete(state, p, endp)) { @@ -7576,32 +7697,28 @@ static llparse_state_t llhttp__internal__run( default: goto s_n_llhttp__internal__n_error_7; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_or_flags_1: { switch (llhttp__internal__c_or_flags_1(state, p, endp)) { default: goto s_n_llhttp__internal__n_invoke_llhttp__after_headers_complete; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_or_flags_2: { switch (llhttp__internal__c_or_flags_1(state, p, endp)) { default: goto s_n_llhttp__internal__n_invoke_llhttp__after_headers_complete; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_update_upgrade: { switch (llhttp__internal__c_update_upgrade(state, p, endp)) { default: goto s_n_llhttp__internal__n_invoke_or_flags_2; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_pause_14: { state->error = 0x15; @@ -7609,8 +7726,7 @@ static llparse_state_t llhttp__internal__run( state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__after_headers_complete; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_error_6: { state->error = 0x11; @@ -7618,8 +7734,7 @@ static llparse_state_t llhttp__internal__run( state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_llhttp__on_headers_complete: { switch (llhttp__on_headers_complete(state, p, endp)) { @@ -7634,16 +7749,14 @@ static llparse_state_t llhttp__internal__run( default: goto s_n_llhttp__internal__n_error_6; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_llhttp__before_headers_complete: { switch (llhttp__before_headers_complete(state, p, endp)) { default: goto s_n_llhttp__internal__n_invoke_llhttp__on_headers_complete; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_test_flags: { switch (llhttp__internal__c_test_flags(state, p, endp)) { @@ -7652,8 +7765,7 @@ static llparse_state_t llhttp__internal__run( default: goto s_n_llhttp__internal__n_invoke_llhttp__before_headers_complete; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_test_lenient_flags_1: { switch (llhttp__internal__c_test_lenient_flags_1(state, p, endp)) { @@ -7662,8 +7774,7 @@ static llparse_state_t llhttp__internal__run( default: goto s_n_llhttp__internal__n_error_5; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_pause_17: { state->error = 0x15; @@ -7671,8 +7782,7 @@ static llparse_state_t llhttp__internal__run( state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__on_message_complete_2; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_error_42: { state->error = 0x14; @@ -7680,8 +7790,7 @@ static llparse_state_t llhttp__internal__run( state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_llhttp__on_chunk_complete_2: { switch (llhttp__on_chunk_complete(state, p, endp)) { @@ -7692,32 +7801,28 @@ static llparse_state_t llhttp__internal__run( default: goto s_n_llhttp__internal__n_error_42; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_or_flags_3: { switch (llhttp__internal__c_or_flags_1(state, p, endp)) { default: goto s_n_llhttp__internal__n_invoke_llhttp__after_headers_complete; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_or_flags_4: { switch (llhttp__internal__c_or_flags_1(state, p, endp)) { default: goto s_n_llhttp__internal__n_invoke_llhttp__after_headers_complete; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_update_upgrade_1: { switch (llhttp__internal__c_update_upgrade(state, p, endp)) { default: goto s_n_llhttp__internal__n_invoke_or_flags_4; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_pause_16: { state->error = 0x15; @@ -7725,8 +7830,7 @@ static llparse_state_t llhttp__internal__run( state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__after_headers_complete; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_error_41: { state->error = 0x11; @@ -7734,8 +7838,7 @@ static llparse_state_t llhttp__internal__run( state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_llhttp__on_headers_complete_1: { switch (llhttp__on_headers_complete(state, p, endp)) { @@ -7750,16 +7853,14 @@ static llparse_state_t llhttp__internal__run( default: goto s_n_llhttp__internal__n_error_41; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_llhttp__before_headers_complete_1: { switch (llhttp__before_headers_complete(state, p, endp)) { default: goto s_n_llhttp__internal__n_invoke_llhttp__on_headers_complete_1; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_test_flags_1: { switch (llhttp__internal__c_test_flags(state, p, endp)) { @@ -7768,8 +7869,7 @@ static llparse_state_t llhttp__internal__run( default: goto s_n_llhttp__internal__n_invoke_llhttp__before_headers_complete_1; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_error_43: { state->error = 0x2; @@ -7777,8 +7877,7 @@ static llparse_state_t llhttp__internal__run( state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_test_lenient_flags_12: { switch (llhttp__internal__c_test_lenient_flags_8(state, p, endp)) { @@ -7787,8 +7886,7 @@ static llparse_state_t llhttp__internal__run( default: goto s_n_llhttp__internal__n_error_43; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_error_44: { state->error = 0xa; @@ -7796,8 +7894,7 @@ static llparse_state_t llhttp__internal__run( state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_span_end_llhttp__on_header_field: { const unsigned char* start; @@ -7814,8 +7911,7 @@ static llparse_state_t llhttp__internal__run( } p++; goto s_n_llhttp__internal__n_error_5; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_test_lenient_flags_13: { switch (llhttp__internal__c_test_lenient_flags(state, p, endp)) { @@ -7824,8 +7920,7 @@ static llparse_state_t llhttp__internal__run( default: goto s_n_llhttp__internal__n_span_end_llhttp__on_header_field; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_error_60: { state->error = 0xb; @@ -7833,8 +7928,7 @@ static llparse_state_t llhttp__internal__run( state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_error_47: { state->error = 0xa; @@ -7842,8 +7936,7 @@ static llparse_state_t llhttp__internal__run( state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_test_lenient_flags_15: { switch (llhttp__internal__c_test_lenient_flags(state, p, endp)) { @@ -7852,8 +7945,7 @@ static llparse_state_t llhttp__internal__run( default: goto s_n_llhttp__internal__n_error_47; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_error_49: { state->error = 0xb; @@ -7861,8 +7953,7 @@ static llparse_state_t llhttp__internal__run( state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_pause_18: { state->error = 0x15; @@ -7870,8 +7961,7 @@ static llparse_state_t llhttp__internal__run( state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_header_field_start; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_error_48: { state->error = 0x1d; @@ -7879,8 +7969,7 @@ static llparse_state_t llhttp__internal__run( state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_span_end_llhttp__on_header_value: { const unsigned char* start; @@ -7896,48 +7985,42 @@ static llparse_state_t llhttp__internal__run( return s_error; } goto s_n_llhttp__internal__n_invoke_llhttp__on_header_value_complete; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_update_header_state: { switch (llhttp__internal__c_update_header_state(state, p, endp)) { default: goto s_n_llhttp__internal__n_span_start_llhttp__on_header_value; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_or_flags_5: { switch (llhttp__internal__c_or_flags_5(state, p, endp)) { default: goto s_n_llhttp__internal__n_invoke_update_header_state; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_or_flags_6: { switch (llhttp__internal__c_or_flags_6(state, p, endp)) { default: goto s_n_llhttp__internal__n_invoke_update_header_state; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_or_flags_7: { switch (llhttp__internal__c_or_flags_7(state, p, endp)) { default: goto s_n_llhttp__internal__n_invoke_update_header_state; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_or_flags_8: { switch (llhttp__internal__c_or_flags_8(state, p, endp)) { default: goto s_n_llhttp__internal__n_span_start_llhttp__on_header_value; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_load_header_state_2: { switch (llhttp__internal__c_load_header_state(state, p, endp)) { @@ -7952,8 +8035,7 @@ static llparse_state_t llhttp__internal__run( default: goto s_n_llhttp__internal__n_span_start_llhttp__on_header_value; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_load_header_state_1: { switch (llhttp__internal__c_load_header_state(state, p, endp)) { @@ -7962,8 +8044,7 @@ static llparse_state_t llhttp__internal__run( default: goto s_n_llhttp__internal__n_invoke_load_header_state_2; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_error_46: { state->error = 0xa; @@ -7971,8 +8052,7 @@ static llparse_state_t llhttp__internal__run( state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_test_lenient_flags_14: { switch (llhttp__internal__c_test_lenient_flags_1(state, p, endp)) { @@ -7981,8 +8061,7 @@ static llparse_state_t llhttp__internal__run( default: goto s_n_llhttp__internal__n_error_46; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_error_50: { state->error = 0x2; @@ -7990,8 +8069,7 @@ static llparse_state_t llhttp__internal__run( state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_test_lenient_flags_16: { switch (llhttp__internal__c_test_lenient_flags(state, p, endp)) { @@ -8000,16 +8078,14 @@ static llparse_state_t llhttp__internal__run( default: goto s_n_llhttp__internal__n_error_50; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_update_header_state_1: { switch (llhttp__internal__c_update_header_state_1(state, p, endp)) { default: goto s_n_llhttp__internal__n_span_start_llhttp__on_header_value_1; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_load_header_state_4: { switch (llhttp__internal__c_load_header_state(state, p, endp)) { @@ -8018,8 +8094,7 @@ static llparse_state_t llhttp__internal__run( default: goto s_n_llhttp__internal__n_span_start_llhttp__on_header_value_1; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_error_52: { state->error = 0xa; @@ -8027,8 +8102,7 @@ static llparse_state_t llhttp__internal__run( state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_test_lenient_flags_18: { switch (llhttp__internal__c_test_lenient_flags(state, p, endp)) { @@ -8037,48 +8111,42 @@ static llparse_state_t llhttp__internal__run( default: goto s_n_llhttp__internal__n_error_52; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_update_header_state_2: { switch (llhttp__internal__c_update_header_state(state, p, endp)) { default: goto s_n_llhttp__internal__n_invoke_llhttp__on_header_value_complete; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_or_flags_9: { switch (llhttp__internal__c_or_flags_5(state, p, endp)) { default: goto s_n_llhttp__internal__n_invoke_update_header_state_2; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_or_flags_10: { switch (llhttp__internal__c_or_flags_6(state, p, endp)) { default: goto s_n_llhttp__internal__n_invoke_update_header_state_2; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_or_flags_11: { switch (llhttp__internal__c_or_flags_7(state, p, endp)) { default: goto s_n_llhttp__internal__n_invoke_update_header_state_2; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_or_flags_12: { switch (llhttp__internal__c_or_flags_8(state, p, endp)) { default: goto s_n_llhttp__internal__n_invoke_llhttp__on_header_value_complete; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_load_header_state_5: { switch (llhttp__internal__c_load_header_state(state, p, endp)) { @@ -8093,8 +8161,7 @@ static llparse_state_t llhttp__internal__run( default: goto s_n_llhttp__internal__n_invoke_llhttp__on_header_value_complete; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_error_53: { state->error = 0x3; @@ -8102,8 +8169,7 @@ static llparse_state_t llhttp__internal__run( state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_error_51: { state->error = 0x19; @@ -8111,8 +8177,7 @@ static llparse_state_t llhttp__internal__run( state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_span_end_llhttp__on_header_value_1: { const unsigned char* start; @@ -8128,8 +8193,7 @@ static llparse_state_t llhttp__internal__run( return s_error; } goto s_n_llhttp__internal__n_invoke_test_lenient_flags_17; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_span_end_llhttp__on_header_value_2: { const unsigned char* start; @@ -8146,8 +8210,7 @@ static llparse_state_t llhttp__internal__run( } p++; goto s_n_llhttp__internal__n_header_value_almost_done; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_span_end_llhttp__on_header_value_4: { const unsigned char* start; @@ -8163,8 +8226,7 @@ static llparse_state_t llhttp__internal__run( return s_error; } goto s_n_llhttp__internal__n_header_value_almost_done; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_span_end_llhttp__on_header_value_5: { const unsigned char* start; @@ -8181,8 +8243,7 @@ static llparse_state_t llhttp__internal__run( } p++; goto s_n_llhttp__internal__n_header_value_almost_done; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_span_end_llhttp__on_header_value_3: { const unsigned char* start; @@ -8198,8 +8259,7 @@ static llparse_state_t llhttp__internal__run( return s_error; } goto s_n_llhttp__internal__n_error_54; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_test_lenient_flags_19: { switch (llhttp__internal__c_test_lenient_flags(state, p, endp)) { @@ -8208,48 +8268,42 @@ static llparse_state_t llhttp__internal__run( default: goto s_n_llhttp__internal__n_span_end_llhttp__on_header_value_3; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_update_header_state_4: { switch (llhttp__internal__c_update_header_state(state, p, endp)) { default: goto s_n_llhttp__internal__n_header_value_connection; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_or_flags_13: { switch (llhttp__internal__c_or_flags_5(state, p, endp)) { default: goto s_n_llhttp__internal__n_invoke_update_header_state_4; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_or_flags_14: { switch (llhttp__internal__c_or_flags_6(state, p, endp)) { default: goto s_n_llhttp__internal__n_invoke_update_header_state_4; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_or_flags_15: { switch (llhttp__internal__c_or_flags_7(state, p, endp)) { default: goto s_n_llhttp__internal__n_invoke_update_header_state_4; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_or_flags_16: { switch (llhttp__internal__c_or_flags_8(state, p, endp)) { default: goto s_n_llhttp__internal__n_header_value_connection; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_load_header_state_6: { switch (llhttp__internal__c_load_header_state(state, p, endp)) { @@ -8264,40 +8318,35 @@ static llparse_state_t llhttp__internal__run( default: goto s_n_llhttp__internal__n_header_value_connection; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_update_header_state_5: { switch (llhttp__internal__c_update_header_state_1(state, p, endp)) { default: goto s_n_llhttp__internal__n_header_value_connection_token; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_update_header_state_3: { switch (llhttp__internal__c_update_header_state_3(state, p, endp)) { default: goto s_n_llhttp__internal__n_header_value_connection_ws; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_update_header_state_6: { switch (llhttp__internal__c_update_header_state_6(state, p, endp)) { default: goto s_n_llhttp__internal__n_header_value_connection_ws; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_update_header_state_7: { switch (llhttp__internal__c_update_header_state_7(state, p, endp)) { default: goto s_n_llhttp__internal__n_header_value_connection_ws; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_span_end_llhttp__on_header_value_6: { const unsigned char* start; @@ -8313,8 +8362,7 @@ static llparse_state_t llhttp__internal__run( return s_error; } goto s_n_llhttp__internal__n_error_56; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_mul_add_content_length_1: { switch (llhttp__internal__c_mul_add_content_length_1(state, p, endp, match)) { @@ -8323,16 +8371,14 @@ static llparse_state_t llhttp__internal__run( default: goto s_n_llhttp__internal__n_header_value_content_length; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_or_flags_17: { switch (llhttp__internal__c_or_flags_17(state, p, endp)) { default: goto s_n_llhttp__internal__n_header_value_otherwise; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_span_end_llhttp__on_header_value_7: { const unsigned char* start; @@ -8348,8 +8394,7 @@ static llparse_state_t llhttp__internal__run( return s_error; } goto s_n_llhttp__internal__n_error_57; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_error_55: { state->error = 0x4; @@ -8357,8 +8402,7 @@ static llparse_state_t llhttp__internal__run( state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_test_flags_2: { switch (llhttp__internal__c_test_flags_2(state, p, endp)) { @@ -8367,8 +8411,7 @@ static llparse_state_t llhttp__internal__run( default: goto s_n_llhttp__internal__n_error_55; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_span_end_llhttp__on_header_value_9: { const unsigned char* start; @@ -8385,16 +8428,14 @@ static llparse_state_t llhttp__internal__run( } p++; goto s_n_llhttp__internal__n_error_59; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_update_header_state_8: { switch (llhttp__internal__c_update_header_state_8(state, p, endp)) { default: goto s_n_llhttp__internal__n_header_value_otherwise; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_span_end_llhttp__on_header_value_8: { const unsigned char* start; @@ -8411,8 +8452,7 @@ static llparse_state_t llhttp__internal__run( } p++; goto s_n_llhttp__internal__n_error_58; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_test_lenient_flags_20: { switch (llhttp__internal__c_test_lenient_flags_20(state, p, endp)) { @@ -8421,8 +8461,7 @@ static llparse_state_t llhttp__internal__run( default: goto s_n_llhttp__internal__n_header_value_te_chunked; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_load_type_1: { switch (llhttp__internal__c_load_type(state, p, endp)) { @@ -8431,32 +8470,28 @@ static llparse_state_t llhttp__internal__run( default: goto s_n_llhttp__internal__n_header_value_te_chunked; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_update_header_state_9: { switch (llhttp__internal__c_update_header_state_1(state, p, endp)) { default: goto s_n_llhttp__internal__n_header_value; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_and_flags: { switch (llhttp__internal__c_and_flags(state, p, endp)) { default: goto s_n_llhttp__internal__n_header_value_te_chunked; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_or_flags_19: { switch (llhttp__internal__c_or_flags_18(state, p, endp)) { default: goto s_n_llhttp__internal__n_invoke_and_flags; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_test_lenient_flags_21: { switch (llhttp__internal__c_test_lenient_flags_20(state, p, endp)) { @@ -8465,8 +8500,7 @@ static llparse_state_t llhttp__internal__run( default: goto s_n_llhttp__internal__n_invoke_or_flags_19; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_load_type_2: { switch (llhttp__internal__c_load_type(state, p, endp)) { @@ -8475,16 +8509,14 @@ static llparse_state_t llhttp__internal__run( default: goto s_n_llhttp__internal__n_invoke_or_flags_19; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_or_flags_18: { switch (llhttp__internal__c_or_flags_18(state, p, endp)) { default: goto s_n_llhttp__internal__n_invoke_and_flags; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_test_flags_3: { switch (llhttp__internal__c_test_flags_3(state, p, endp)) { @@ -8493,16 +8525,14 @@ static llparse_state_t llhttp__internal__run( default: goto s_n_llhttp__internal__n_invoke_or_flags_18; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_or_flags_20: { switch (llhttp__internal__c_or_flags_20(state, p, endp)) { default: goto s_n_llhttp__internal__n_invoke_update_header_state_9; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_load_header_state_3: { switch (llhttp__internal__c_load_header_state(state, p, endp)) { @@ -8517,8 +8547,7 @@ static llparse_state_t llhttp__internal__run( default: goto s_n_llhttp__internal__n_header_value; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_test_lenient_flags_22: { switch (llhttp__internal__c_test_lenient_flags_22(state, p, endp)) { @@ -8527,8 +8556,7 @@ static llparse_state_t llhttp__internal__run( default: goto s_n_llhttp__internal__n_header_value_discard_ws; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_test_flags_4: { switch (llhttp__internal__c_test_flags_4(state, p, endp)) { @@ -8537,8 +8565,7 @@ static llparse_state_t llhttp__internal__run( default: goto s_n_llhttp__internal__n_header_value_discard_ws; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_error_61: { state->error = 0xf; @@ -8546,8 +8573,7 @@ static llparse_state_t llhttp__internal__run( state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_test_lenient_flags_23: { switch (llhttp__internal__c_test_lenient_flags_22(state, p, endp)) { @@ -8556,8 +8582,7 @@ static llparse_state_t llhttp__internal__run( default: goto s_n_llhttp__internal__n_header_value_discard_ws; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_test_flags_5: { switch (llhttp__internal__c_test_flags_2(state, p, endp)) { @@ -8566,8 +8591,7 @@ static llparse_state_t llhttp__internal__run( default: goto s_n_llhttp__internal__n_header_value_discard_ws; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_pause_19: { state->error = 0x15; @@ -8575,8 +8599,7 @@ static llparse_state_t llhttp__internal__run( state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_load_header_state; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_error_45: { state->error = 0x1c; @@ -8584,8 +8607,7 @@ static llparse_state_t llhttp__internal__run( state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_span_end_llhttp__on_header_field_1: { const unsigned char* start; @@ -8602,8 +8624,7 @@ static llparse_state_t llhttp__internal__run( } p++; goto s_n_llhttp__internal__n_invoke_llhttp__on_header_field_complete; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_span_end_llhttp__on_header_field_2: { const unsigned char* start; @@ -8620,8 +8641,7 @@ static llparse_state_t llhttp__internal__run( } p++; goto s_n_llhttp__internal__n_invoke_llhttp__on_header_field_complete; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_error_62: { state->error = 0xa; @@ -8629,32 +8649,28 @@ static llparse_state_t llhttp__internal__run( state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_update_header_state_10: { switch (llhttp__internal__c_update_header_state_1(state, p, endp)) { default: goto s_n_llhttp__internal__n_header_field_general; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_store_header_state: { switch (llhttp__internal__c_store_header_state(state, p, endp, match)) { default: goto s_n_llhttp__internal__n_header_field_colon; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_update_header_state_11: { switch (llhttp__internal__c_update_header_state_1(state, p, endp)) { default: goto s_n_llhttp__internal__n_header_field_general; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_error_4: { state->error = 0x1e; @@ -8662,8 +8678,7 @@ static llparse_state_t llhttp__internal__run( state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_test_lenient_flags: { switch (llhttp__internal__c_test_lenient_flags(state, p, endp)) { @@ -8672,8 +8687,7 @@ static llparse_state_t llhttp__internal__run( default: goto s_n_llhttp__internal__n_error_4; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_pause_20: { state->error = 0x15; @@ -8681,8 +8695,7 @@ static llparse_state_t llhttp__internal__run( state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_headers_start; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_error_3: { state->error = 0x1a; @@ -8690,8 +8703,7 @@ static llparse_state_t llhttp__internal__run( state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_llhttp__on_url_complete: { switch (llhttp__on_url_complete(state, p, endp)) { @@ -8702,24 +8714,21 @@ static llparse_state_t llhttp__internal__run( default: goto s_n_llhttp__internal__n_error_3; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_update_http_minor: { switch (llhttp__internal__c_update_http_minor(state, p, endp)) { default: goto s_n_llhttp__internal__n_invoke_llhttp__on_url_complete; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_update_http_major: { switch (llhttp__internal__c_update_http_major(state, p, endp)) { default: goto s_n_llhttp__internal__n_invoke_update_http_minor; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_span_end_llhttp__on_url_3: { const unsigned char* start; @@ -8735,8 +8744,7 @@ static llparse_state_t llhttp__internal__run( return s_error; } goto s_n_llhttp__internal__n_url_skip_to_http09; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_error_63: { state->error = 0x7; @@ -8744,8 +8752,7 @@ static llparse_state_t llhttp__internal__run( state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_span_end_llhttp__on_url_4: { const unsigned char* start; @@ -8761,73 +8768,65 @@ static llparse_state_t llhttp__internal__run( return s_error; } goto s_n_llhttp__internal__n_url_skip_lf_to_http09; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } - s_n_llhttp__internal__n_error_71: { + s_n_llhttp__internal__n_error_72: { state->error = 0x17; state->reason = "Pause on PRI/Upgrade"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } - s_n_llhttp__internal__n_error_72: { + s_n_llhttp__internal__n_error_73: { state->error = 0x9; state->reason = "Expected HTTP/2 Connection Preface"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } - s_n_llhttp__internal__n_error_69: { + s_n_llhttp__internal__n_error_70: { state->error = 0x2; state->reason = "Expected CRLF after version"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_test_lenient_flags_26: { switch (llhttp__internal__c_test_lenient_flags_8(state, p, endp)) { case 1: goto s_n_llhttp__internal__n_headers_start; default: - goto s_n_llhttp__internal__n_error_69; + goto s_n_llhttp__internal__n_error_70; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } - s_n_llhttp__internal__n_error_68: { + s_n_llhttp__internal__n_error_69: { state->error = 0x9; state->reason = "Expected CRLF after version"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_test_lenient_flags_25: { switch (llhttp__internal__c_test_lenient_flags_1(state, p, endp)) { case 1: goto s_n_llhttp__internal__n_req_http_complete_crlf; default: - goto s_n_llhttp__internal__n_error_68; + goto s_n_llhttp__internal__n_error_69; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } - s_n_llhttp__internal__n_error_70: { + s_n_llhttp__internal__n_error_71: { state->error = 0x9; state->reason = "Expected CRLF after version"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_pause_21: { state->error = 0x15; @@ -8835,17 +8834,15 @@ static llparse_state_t llhttp__internal__run( state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_load_method_1; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } - s_n_llhttp__internal__n_error_67: { + s_n_llhttp__internal__n_error_68: { state->error = 0x21; state->reason = "`on_version_complete` callback error"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_span_end_llhttp__on_version_1: { const unsigned char* start; @@ -8861,8 +8858,7 @@ static llparse_state_t llhttp__internal__run( return s_error; } goto s_n_llhttp__internal__n_invoke_llhttp__on_version_complete; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_span_end_llhttp__on_version: { const unsigned char* start; @@ -8874,12 +8870,11 @@ static llparse_state_t llhttp__internal__run( if (err != 0) { state->error = err; state->error_pos = (const char*) p; - state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_error_66; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_error_67; return s_error; } - goto s_n_llhttp__internal__n_error_66; - /* UNREACHABLE */; - abort(); + goto s_n_llhttp__internal__n_error_67; + UNREACHABLE; } s_n_llhttp__internal__n_invoke_load_http_minor: { switch (llhttp__internal__c_load_http_minor(state, p, endp)) { @@ -8888,8 +8883,7 @@ static llparse_state_t llhttp__internal__run( default: goto s_n_llhttp__internal__n_span_end_llhttp__on_version; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_load_http_minor_1: { switch (llhttp__internal__c_load_http_minor(state, p, endp)) { @@ -8900,8 +8894,7 @@ static llparse_state_t llhttp__internal__run( default: goto s_n_llhttp__internal__n_span_end_llhttp__on_version; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_load_http_minor_2: { switch (llhttp__internal__c_load_http_minor(state, p, endp)) { @@ -8910,8 +8903,7 @@ static llparse_state_t llhttp__internal__run( default: goto s_n_llhttp__internal__n_span_end_llhttp__on_version; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_load_http_major: { switch (llhttp__internal__c_load_http_major(state, p, endp)) { @@ -8924,8 +8916,7 @@ static llparse_state_t llhttp__internal__run( default: goto s_n_llhttp__internal__n_span_end_llhttp__on_version; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_test_lenient_flags_24: { switch (llhttp__internal__c_test_lenient_flags_24(state, p, endp)) { @@ -8934,16 +8925,14 @@ static llparse_state_t llhttp__internal__run( default: goto s_n_llhttp__internal__n_invoke_load_http_major; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_store_http_minor: { switch (llhttp__internal__c_store_http_minor(state, p, endp, match)) { default: goto s_n_llhttp__internal__n_invoke_test_lenient_flags_24; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_span_end_llhttp__on_version_2: { const unsigned char* start; @@ -8955,12 +8944,11 @@ static llparse_state_t llhttp__internal__run( if (err != 0) { state->error = err; state->error_pos = (const char*) p; - state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_error_73; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_error_74; return s_error; } - goto s_n_llhttp__internal__n_error_73; - /* UNREACHABLE */; - abort(); + goto s_n_llhttp__internal__n_error_74; + UNREACHABLE; } s_n_llhttp__internal__n_span_end_llhttp__on_version_3: { const unsigned char* start; @@ -8972,20 +8960,18 @@ static llparse_state_t llhttp__internal__run( if (err != 0) { state->error = err; state->error_pos = (const char*) p; - state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_error_74; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_error_75; return s_error; } - goto s_n_llhttp__internal__n_error_74; - /* UNREACHABLE */; - abort(); + goto s_n_llhttp__internal__n_error_75; + UNREACHABLE; } s_n_llhttp__internal__n_invoke_store_http_major: { switch (llhttp__internal__c_store_http_major(state, p, endp, match)) { default: goto s_n_llhttp__internal__n_req_http_dot; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_span_end_llhttp__on_version_4: { const unsigned char* start; @@ -8997,183 +8983,163 @@ static llparse_state_t llhttp__internal__run( if (err != 0) { state->error = err; state->error_pos = (const char*) p; - state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_error_75; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_error_76; return s_error; } - goto s_n_llhttp__internal__n_error_75; - /* UNREACHABLE */; - abort(); + goto s_n_llhttp__internal__n_error_76; + UNREACHABLE; } - s_n_llhttp__internal__n_error_65: { + s_n_llhttp__internal__n_error_77: { + state->error = 0x8; + state->reason = "Expected HTTP/, RTSP/ or ICE/"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + UNREACHABLE; + } + s_n_llhttp__internal__n_error_66: { state->error = 0x8; state->reason = "Invalid method for HTTP/x.x request"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } - s_n_llhttp__internal__n_invoke_load_method: { - switch (llhttp__internal__c_load_method(state, p, endp)) { - case 0: - goto s_n_llhttp__internal__n_span_start_llhttp__on_version; - case 1: - goto s_n_llhttp__internal__n_span_start_llhttp__on_version; - case 2: - goto s_n_llhttp__internal__n_span_start_llhttp__on_version; - case 3: - goto s_n_llhttp__internal__n_span_start_llhttp__on_version; - case 4: - goto s_n_llhttp__internal__n_span_start_llhttp__on_version; - case 5: - goto s_n_llhttp__internal__n_span_start_llhttp__on_version; - case 6: - goto s_n_llhttp__internal__n_span_start_llhttp__on_version; - case 7: - goto s_n_llhttp__internal__n_span_start_llhttp__on_version; - case 8: - goto s_n_llhttp__internal__n_span_start_llhttp__on_version; - case 9: - goto s_n_llhttp__internal__n_span_start_llhttp__on_version; - case 10: - goto s_n_llhttp__internal__n_span_start_llhttp__on_version; - case 11: - goto s_n_llhttp__internal__n_span_start_llhttp__on_version; - case 12: - goto s_n_llhttp__internal__n_span_start_llhttp__on_version; - case 13: - goto s_n_llhttp__internal__n_span_start_llhttp__on_version; - case 14: - goto s_n_llhttp__internal__n_span_start_llhttp__on_version; - case 15: - goto s_n_llhttp__internal__n_span_start_llhttp__on_version; - case 16: - goto s_n_llhttp__internal__n_span_start_llhttp__on_version; - case 17: - goto s_n_llhttp__internal__n_span_start_llhttp__on_version; - case 18: - goto s_n_llhttp__internal__n_span_start_llhttp__on_version; - case 19: - goto s_n_llhttp__internal__n_span_start_llhttp__on_version; - case 20: - goto s_n_llhttp__internal__n_span_start_llhttp__on_version; - case 21: - goto s_n_llhttp__internal__n_span_start_llhttp__on_version; - case 22: - goto s_n_llhttp__internal__n_span_start_llhttp__on_version; - case 23: - goto s_n_llhttp__internal__n_span_start_llhttp__on_version; - case 24: - goto s_n_llhttp__internal__n_span_start_llhttp__on_version; - case 25: - goto s_n_llhttp__internal__n_span_start_llhttp__on_version; - case 26: - goto s_n_llhttp__internal__n_span_start_llhttp__on_version; - case 27: - goto s_n_llhttp__internal__n_span_start_llhttp__on_version; - case 28: - goto s_n_llhttp__internal__n_span_start_llhttp__on_version; - case 29: - goto s_n_llhttp__internal__n_span_start_llhttp__on_version; - case 30: - goto s_n_llhttp__internal__n_span_start_llhttp__on_version; - case 31: - goto s_n_llhttp__internal__n_span_start_llhttp__on_version; - case 32: - goto s_n_llhttp__internal__n_span_start_llhttp__on_version; - case 33: - goto s_n_llhttp__internal__n_span_start_llhttp__on_version; - case 34: - goto s_n_llhttp__internal__n_span_start_llhttp__on_version; - case 46: - goto s_n_llhttp__internal__n_span_start_llhttp__on_version; - default: - goto s_n_llhttp__internal__n_error_65; - } - /* UNREACHABLE */; - abort(); + s_n_llhttp__internal__n_pause_22: { + state->error = 0x15; + state->reason = "on_protocol_complete pause"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_load_method; + return s_error; + UNREACHABLE; } - s_n_llhttp__internal__n_error_78: { - state->error = 0x8; - state->reason = "Expected HTTP/"; + s_n_llhttp__internal__n_error_65: { + state->error = 0x26; + state->reason = "`on_protocol_complete` callback error"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; + } + s_n_llhttp__internal__n_span_end_llhttp__on_protocol: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_protocol(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__on_protocol_complete; + return s_error; + } + goto s_n_llhttp__internal__n_invoke_llhttp__on_protocol_complete; + UNREACHABLE; + } + s_n_llhttp__internal__n_span_end_llhttp__on_protocol_3: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_protocol(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_error_82; + return s_error; + } + goto s_n_llhttp__internal__n_error_82; + UNREACHABLE; } - s_n_llhttp__internal__n_error_76: { + s_n_llhttp__internal__n_error_79: { state->error = 0x8; state->reason = "Expected SOURCE method for ICE/x.x request"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } - s_n_llhttp__internal__n_invoke_load_method_2: { - switch (llhttp__internal__c_load_method(state, p, endp)) { - case 33: - goto s_n_llhttp__internal__n_span_start_llhttp__on_version; - default: - goto s_n_llhttp__internal__n_error_76; + s_n_llhttp__internal__n_pause_23: { + state->error = 0x15; + state->reason = "on_protocol_complete pause"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_load_method_2; + return s_error; + UNREACHABLE; + } + s_n_llhttp__internal__n_error_78: { + state->error = 0x26; + state->reason = "`on_protocol_complete` callback error"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + UNREACHABLE; + } + s_n_llhttp__internal__n_span_end_llhttp__on_protocol_1: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_protocol(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__on_protocol_complete_1; + return s_error; } - /* UNREACHABLE */; - abort(); + goto s_n_llhttp__internal__n_invoke_llhttp__on_protocol_complete_1; + UNREACHABLE; } - s_n_llhttp__internal__n_error_77: { + s_n_llhttp__internal__n_error_81: { state->error = 0x8; state->reason = "Invalid method for RTSP/x.x request"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } - s_n_llhttp__internal__n_invoke_load_method_3: { - switch (llhttp__internal__c_load_method(state, p, endp)) { - case 1: - goto s_n_llhttp__internal__n_span_start_llhttp__on_version; - case 3: - goto s_n_llhttp__internal__n_span_start_llhttp__on_version; - case 6: - goto s_n_llhttp__internal__n_span_start_llhttp__on_version; - case 35: - goto s_n_llhttp__internal__n_span_start_llhttp__on_version; - case 36: - goto s_n_llhttp__internal__n_span_start_llhttp__on_version; - case 37: - goto s_n_llhttp__internal__n_span_start_llhttp__on_version; - case 38: - goto s_n_llhttp__internal__n_span_start_llhttp__on_version; - case 39: - goto s_n_llhttp__internal__n_span_start_llhttp__on_version; - case 40: - goto s_n_llhttp__internal__n_span_start_llhttp__on_version; - case 41: - goto s_n_llhttp__internal__n_span_start_llhttp__on_version; - case 42: - goto s_n_llhttp__internal__n_span_start_llhttp__on_version; - case 43: - goto s_n_llhttp__internal__n_span_start_llhttp__on_version; - case 44: - goto s_n_llhttp__internal__n_span_start_llhttp__on_version; - case 45: - goto s_n_llhttp__internal__n_span_start_llhttp__on_version; - default: - goto s_n_llhttp__internal__n_error_77; + s_n_llhttp__internal__n_pause_24: { + state->error = 0x15; + state->reason = "on_protocol_complete pause"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_load_method_3; + return s_error; + UNREACHABLE; + } + s_n_llhttp__internal__n_error_80: { + state->error = 0x26; + state->reason = "`on_protocol_complete` callback error"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + UNREACHABLE; + } + s_n_llhttp__internal__n_span_end_llhttp__on_protocol_2: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_protocol(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__on_protocol_complete_2; + return s_error; } - /* UNREACHABLE */; - abort(); + goto s_n_llhttp__internal__n_invoke_llhttp__on_protocol_complete_2; + UNREACHABLE; } - s_n_llhttp__internal__n_pause_22: { + s_n_llhttp__internal__n_pause_25: { state->error = 0x15; state->reason = "on_url_complete pause"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_req_http_start; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_error_64: { state->error = 0x1a; @@ -9181,20 +9147,18 @@ static llparse_state_t llhttp__internal__run( state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_llhttp__on_url_complete_1: { switch (llhttp__on_url_complete(state, p, endp)) { case 0: goto s_n_llhttp__internal__n_req_http_start; case 21: - goto s_n_llhttp__internal__n_pause_22; + goto s_n_llhttp__internal__n_pause_25; default: goto s_n_llhttp__internal__n_error_64; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_span_end_llhttp__on_url_5: { const unsigned char* start; @@ -9210,8 +9174,7 @@ static llparse_state_t llhttp__internal__run( return s_error; } goto s_n_llhttp__internal__n_url_skip_to_http; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_span_end_llhttp__on_url_6: { const unsigned char* start; @@ -9227,8 +9190,7 @@ static llparse_state_t llhttp__internal__run( return s_error; } goto s_n_llhttp__internal__n_url_skip_to_http09; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_span_end_llhttp__on_url_7: { const unsigned char* start; @@ -9244,8 +9206,7 @@ static llparse_state_t llhttp__internal__run( return s_error; } goto s_n_llhttp__internal__n_url_skip_lf_to_http09; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_span_end_llhttp__on_url_8: { const unsigned char* start; @@ -9261,17 +9222,15 @@ static llparse_state_t llhttp__internal__run( return s_error; } goto s_n_llhttp__internal__n_url_skip_to_http; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } - s_n_llhttp__internal__n_error_79: { + s_n_llhttp__internal__n_error_83: { state->error = 0x7; state->reason = "Invalid char in url fragment start"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_span_end_llhttp__on_url_9: { const unsigned char* start; @@ -9287,8 +9246,7 @@ static llparse_state_t llhttp__internal__run( return s_error; } goto s_n_llhttp__internal__n_url_skip_to_http09; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_span_end_llhttp__on_url_10: { const unsigned char* start; @@ -9304,8 +9262,7 @@ static llparse_state_t llhttp__internal__run( return s_error; } goto s_n_llhttp__internal__n_url_skip_lf_to_http09; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_span_end_llhttp__on_url_11: { const unsigned char* start; @@ -9321,26 +9278,23 @@ static llparse_state_t llhttp__internal__run( return s_error; } goto s_n_llhttp__internal__n_url_skip_to_http; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } - s_n_llhttp__internal__n_error_80: { + s_n_llhttp__internal__n_error_84: { state->error = 0x7; state->reason = "Invalid char in url query"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } - s_n_llhttp__internal__n_error_81: { + s_n_llhttp__internal__n_error_85: { state->error = 0x7; state->reason = "Invalid char in url path"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_span_end_llhttp__on_url: { const unsigned char* start; @@ -9356,8 +9310,7 @@ static llparse_state_t llhttp__internal__run( return s_error; } goto s_n_llhttp__internal__n_url_skip_to_http09; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_span_end_llhttp__on_url_1: { const unsigned char* start; @@ -9373,8 +9326,7 @@ static llparse_state_t llhttp__internal__run( return s_error; } goto s_n_llhttp__internal__n_url_skip_lf_to_http09; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_span_end_llhttp__on_url_2: { const unsigned char* start; @@ -9390,8 +9342,7 @@ static llparse_state_t llhttp__internal__run( return s_error; } goto s_n_llhttp__internal__n_url_skip_to_http; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_span_end_llhttp__on_url_12: { const unsigned char* start; @@ -9407,8 +9358,7 @@ static llparse_state_t llhttp__internal__run( return s_error; } goto s_n_llhttp__internal__n_url_skip_to_http09; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_span_end_llhttp__on_url_13: { const unsigned char* start; @@ -9424,8 +9374,7 @@ static llparse_state_t llhttp__internal__run( return s_error; } goto s_n_llhttp__internal__n_url_skip_lf_to_http09; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_span_end_llhttp__on_url_14: { const unsigned char* start; @@ -9441,62 +9390,55 @@ static llparse_state_t llhttp__internal__run( return s_error; } goto s_n_llhttp__internal__n_url_skip_to_http; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } - s_n_llhttp__internal__n_error_82: { + s_n_llhttp__internal__n_error_86: { state->error = 0x7; state->reason = "Double @ in url"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } - s_n_llhttp__internal__n_error_83: { + s_n_llhttp__internal__n_error_87: { state->error = 0x7; state->reason = "Unexpected char in url server"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } - s_n_llhttp__internal__n_error_84: { + s_n_llhttp__internal__n_error_88: { state->error = 0x7; state->reason = "Unexpected char in url server"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } - s_n_llhttp__internal__n_error_85: { + s_n_llhttp__internal__n_error_89: { state->error = 0x7; state->reason = "Unexpected char in url schema"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } - s_n_llhttp__internal__n_error_86: { + s_n_llhttp__internal__n_error_90: { state->error = 0x7; state->reason = "Unexpected char in url schema"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } - s_n_llhttp__internal__n_error_87: { + s_n_llhttp__internal__n_error_91: { state->error = 0x7; state->reason = "Unexpected start char in url"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_is_equal_method: { switch (llhttp__internal__c_is_equal_method(state, p, endp)) { @@ -9505,35 +9447,31 @@ static llparse_state_t llhttp__internal__run( default: goto s_n_llhttp__internal__n_url_entry_connect; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } - s_n_llhttp__internal__n_error_88: { + s_n_llhttp__internal__n_error_92: { state->error = 0x6; state->reason = "Expected space after method"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } - s_n_llhttp__internal__n_pause_26: { + s_n_llhttp__internal__n_pause_29: { state->error = 0x15; state->reason = "on_method_complete pause"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_req_first_space_before_url; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } - s_n_llhttp__internal__n_error_107: { + s_n_llhttp__internal__n_error_111: { state->error = 0x20; state->reason = "`on_method_complete` callback error"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_span_end_llhttp__on_method_2: { const unsigned char* start; @@ -9549,129 +9487,115 @@ static llparse_state_t llhttp__internal__run( return s_error; } goto s_n_llhttp__internal__n_invoke_llhttp__on_method_complete_1; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_store_method_1: { switch (llhttp__internal__c_store_method(state, p, endp, match)) { default: goto s_n_llhttp__internal__n_span_end_llhttp__on_method_2; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } - s_n_llhttp__internal__n_error_108: { + s_n_llhttp__internal__n_error_112: { state->error = 0x6; state->reason = "Invalid method encountered"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } - s_n_llhttp__internal__n_error_100: { + s_n_llhttp__internal__n_error_104: { state->error = 0xd; state->reason = "Invalid status code"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } - s_n_llhttp__internal__n_error_98: { + s_n_llhttp__internal__n_error_102: { state->error = 0xd; state->reason = "Invalid status code"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } - s_n_llhttp__internal__n_error_96: { + s_n_llhttp__internal__n_error_100: { state->error = 0xd; state->reason = "Invalid status code"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } - s_n_llhttp__internal__n_pause_24: { + s_n_llhttp__internal__n_pause_27: { state->error = 0x15; state->reason = "on_status_complete pause"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_headers_start; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } - s_n_llhttp__internal__n_error_92: { + s_n_llhttp__internal__n_error_96: { state->error = 0x1b; state->reason = "`on_status_complete` callback error"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_llhttp__on_status_complete: { switch (llhttp__on_status_complete(state, p, endp)) { case 0: goto s_n_llhttp__internal__n_headers_start; case 21: - goto s_n_llhttp__internal__n_pause_24; + goto s_n_llhttp__internal__n_pause_27; default: - goto s_n_llhttp__internal__n_error_92; + goto s_n_llhttp__internal__n_error_96; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } - s_n_llhttp__internal__n_error_91: { + s_n_llhttp__internal__n_error_95: { state->error = 0xd; state->reason = "Invalid response status"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_test_lenient_flags_28: { switch (llhttp__internal__c_test_lenient_flags_1(state, p, endp)) { case 1: goto s_n_llhttp__internal__n_invoke_llhttp__on_status_complete; default: - goto s_n_llhttp__internal__n_error_91; + goto s_n_llhttp__internal__n_error_95; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } - s_n_llhttp__internal__n_error_93: { + s_n_llhttp__internal__n_error_97: { state->error = 0x2; state->reason = "Expected LF after CR"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_test_lenient_flags_29: { switch (llhttp__internal__c_test_lenient_flags_8(state, p, endp)) { case 1: goto s_n_llhttp__internal__n_invoke_llhttp__on_status_complete; default: - goto s_n_llhttp__internal__n_error_93; + goto s_n_llhttp__internal__n_error_97; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } - s_n_llhttp__internal__n_error_94: { + s_n_llhttp__internal__n_error_98: { state->error = 0x19; state->reason = "Missing expected CR after response line"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_span_end_llhttp__on_status: { const unsigned char* start; @@ -9688,8 +9612,7 @@ static llparse_state_t llhttp__internal__run( } p++; goto s_n_llhttp__internal__n_invoke_test_lenient_flags_30; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_span_end_llhttp__on_status_1: { const unsigned char* start; @@ -9706,109 +9629,97 @@ static llparse_state_t llhttp__internal__run( } p++; goto s_n_llhttp__internal__n_res_line_almost_done; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } - s_n_llhttp__internal__n_error_95: { + s_n_llhttp__internal__n_error_99: { state->error = 0xd; state->reason = "Invalid response status"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_mul_add_status_code_2: { switch (llhttp__internal__c_mul_add_status_code(state, p, endp, match)) { case 1: - goto s_n_llhttp__internal__n_error_96; + goto s_n_llhttp__internal__n_error_100; default: goto s_n_llhttp__internal__n_res_status_code_otherwise; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } - s_n_llhttp__internal__n_error_97: { + s_n_llhttp__internal__n_error_101: { state->error = 0xd; state->reason = "Invalid status code"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_mul_add_status_code_1: { switch (llhttp__internal__c_mul_add_status_code(state, p, endp, match)) { case 1: - goto s_n_llhttp__internal__n_error_98; + goto s_n_llhttp__internal__n_error_102; default: goto s_n_llhttp__internal__n_res_status_code_digit_3; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } - s_n_llhttp__internal__n_error_99: { + s_n_llhttp__internal__n_error_103: { state->error = 0xd; state->reason = "Invalid status code"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_mul_add_status_code: { switch (llhttp__internal__c_mul_add_status_code(state, p, endp, match)) { case 1: - goto s_n_llhttp__internal__n_error_100; + goto s_n_llhttp__internal__n_error_104; default: goto s_n_llhttp__internal__n_res_status_code_digit_2; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } - s_n_llhttp__internal__n_error_101: { + s_n_llhttp__internal__n_error_105: { state->error = 0xd; state->reason = "Invalid status code"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_update_status_code: { switch (llhttp__internal__c_update_status_code(state, p, endp)) { default: goto s_n_llhttp__internal__n_res_status_code_digit_1; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } - s_n_llhttp__internal__n_error_102: { + s_n_llhttp__internal__n_error_106: { state->error = 0x9; state->reason = "Expected space after version"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } - s_n_llhttp__internal__n_pause_25: { + s_n_llhttp__internal__n_pause_28: { state->error = 0x15; state->reason = "on_version_complete pause"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_res_after_version; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } - s_n_llhttp__internal__n_error_90: { + s_n_llhttp__internal__n_error_94: { state->error = 0x21; state->reason = "`on_version_complete` callback error"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_span_end_llhttp__on_version_6: { const unsigned char* start; @@ -9824,8 +9735,7 @@ static llparse_state_t llhttp__internal__run( return s_error; } goto s_n_llhttp__internal__n_invoke_llhttp__on_version_complete_1; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_span_end_llhttp__on_version_5: { const unsigned char* start; @@ -9837,12 +9747,11 @@ static llparse_state_t llhttp__internal__run( if (err != 0) { state->error = err; state->error_pos = (const char*) p; - state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_error_89; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_error_93; return s_error; } - goto s_n_llhttp__internal__n_error_89; - /* UNREACHABLE */; - abort(); + goto s_n_llhttp__internal__n_error_93; + UNREACHABLE; } s_n_llhttp__internal__n_invoke_load_http_minor_3: { switch (llhttp__internal__c_load_http_minor(state, p, endp)) { @@ -9851,8 +9760,7 @@ static llparse_state_t llhttp__internal__run( default: goto s_n_llhttp__internal__n_span_end_llhttp__on_version_5; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_load_http_minor_4: { switch (llhttp__internal__c_load_http_minor(state, p, endp)) { @@ -9863,8 +9771,7 @@ static llparse_state_t llhttp__internal__run( default: goto s_n_llhttp__internal__n_span_end_llhttp__on_version_5; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_load_http_minor_5: { switch (llhttp__internal__c_load_http_minor(state, p, endp)) { @@ -9873,8 +9780,7 @@ static llparse_state_t llhttp__internal__run( default: goto s_n_llhttp__internal__n_span_end_llhttp__on_version_5; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_load_http_major_1: { switch (llhttp__internal__c_load_http_major(state, p, endp)) { @@ -9887,8 +9793,7 @@ static llparse_state_t llhttp__internal__run( default: goto s_n_llhttp__internal__n_span_end_llhttp__on_version_5; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_test_lenient_flags_27: { switch (llhttp__internal__c_test_lenient_flags_24(state, p, endp)) { @@ -9897,16 +9802,14 @@ static llparse_state_t llhttp__internal__run( default: goto s_n_llhttp__internal__n_invoke_load_http_major_1; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_store_http_minor_1: { switch (llhttp__internal__c_store_http_minor(state, p, endp, match)) { default: goto s_n_llhttp__internal__n_invoke_test_lenient_flags_27; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_span_end_llhttp__on_version_7: { const unsigned char* start; @@ -9918,12 +9821,11 @@ static llparse_state_t llhttp__internal__run( if (err != 0) { state->error = err; state->error_pos = (const char*) p; - state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_error_103; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_error_107; return s_error; } - goto s_n_llhttp__internal__n_error_103; - /* UNREACHABLE */; - abort(); + goto s_n_llhttp__internal__n_error_107; + UNREACHABLE; } s_n_llhttp__internal__n_span_end_llhttp__on_version_8: { const unsigned char* start; @@ -9935,20 +9837,18 @@ static llparse_state_t llhttp__internal__run( if (err != 0) { state->error = err; state->error_pos = (const char*) p; - state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_error_104; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_error_108; return s_error; } - goto s_n_llhttp__internal__n_error_104; - /* UNREACHABLE */; - abort(); + goto s_n_llhttp__internal__n_error_108; + UNREACHABLE; } s_n_llhttp__internal__n_invoke_store_http_major_1: { switch (llhttp__internal__c_store_http_major(state, p, endp, match)) { default: goto s_n_llhttp__internal__n_res_http_dot; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_span_end_llhttp__on_version_9: { const unsigned char* start; @@ -9960,30 +9860,75 @@ static llparse_state_t llhttp__internal__run( if (err != 0) { state->error = err; state->error_pos = (const char*) p; - state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_error_105; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_error_109; return s_error; } - goto s_n_llhttp__internal__n_error_105; - /* UNREACHABLE */; - abort(); + goto s_n_llhttp__internal__n_error_109; + UNREACHABLE; } - s_n_llhttp__internal__n_error_109: { + s_n_llhttp__internal__n_error_114: { state->error = 0x8; - state->reason = "Expected HTTP/"; + state->reason = "Expected HTTP/, RTSP/ or ICE/"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } - s_n_llhttp__internal__n_pause_23: { + s_n_llhttp__internal__n_pause_30: { + state->error = 0x15; + state->reason = "on_protocol_complete pause"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_res_after_protocol; + return s_error; + UNREACHABLE; + } + s_n_llhttp__internal__n_error_113: { + state->error = 0x26; + state->reason = "`on_protocol_complete` callback error"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + UNREACHABLE; + } + s_n_llhttp__internal__n_span_end_llhttp__on_protocol_4: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_protocol(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__on_protocol_complete_3; + return s_error; + } + goto s_n_llhttp__internal__n_invoke_llhttp__on_protocol_complete_3; + UNREACHABLE; + } + s_n_llhttp__internal__n_span_end_llhttp__on_protocol_5: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_protocol(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_error_115; + return s_error; + } + goto s_n_llhttp__internal__n_error_115; + UNREACHABLE; + } + s_n_llhttp__internal__n_pause_26: { state->error = 0x15; state->reason = "on_method_complete pause"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_req_first_space_before_url; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_error_1: { state->error = 0x20; @@ -9991,8 +9936,7 @@ static llparse_state_t llhttp__internal__run( state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_span_end_llhttp__on_method: { const unsigned char* start; @@ -10008,33 +9952,29 @@ static llparse_state_t llhttp__internal__run( return s_error; } goto s_n_llhttp__internal__n_invoke_llhttp__on_method_complete; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_update_type: { switch (llhttp__internal__c_update_type(state, p, endp)) { default: goto s_n_llhttp__internal__n_span_end_llhttp__on_method; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_store_method: { switch (llhttp__internal__c_store_method(state, p, endp, match)) { default: goto s_n_llhttp__internal__n_invoke_update_type; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } - s_n_llhttp__internal__n_error_106: { + s_n_llhttp__internal__n_error_110: { state->error = 0x8; state->reason = "Invalid word encountered"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_span_end_llhttp__on_method_1: { const unsigned char* start; @@ -10050,25 +9990,22 @@ static llparse_state_t llhttp__internal__run( return s_error; } goto s_n_llhttp__internal__n_invoke_update_type_1; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_update_type_2: { switch (llhttp__internal__c_update_type(state, p, endp)) { default: goto s_n_llhttp__internal__n_span_start_llhttp__on_method_1; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } - s_n_llhttp__internal__n_pause_27: { + s_n_llhttp__internal__n_pause_31: { state->error = 0x15; state->reason = "on_message_begin pause"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_load_type; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_error: { state->error = 0x10; @@ -10076,50 +10013,45 @@ static llparse_state_t llhttp__internal__run( state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_llhttp__on_message_begin: { switch (llhttp__on_message_begin(state, p, endp)) { case 0: goto s_n_llhttp__internal__n_invoke_load_type; case 21: - goto s_n_llhttp__internal__n_pause_27; + goto s_n_llhttp__internal__n_pause_31; default: goto s_n_llhttp__internal__n_error; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } - s_n_llhttp__internal__n_pause_28: { + s_n_llhttp__internal__n_pause_32: { state->error = 0x15; state->reason = "on_reset pause"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_update_finish; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } - s_n_llhttp__internal__n_error_110: { + s_n_llhttp__internal__n_error_116: { state->error = 0x1f; state->reason = "`on_reset` callback error"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_llhttp__on_reset: { switch (llhttp__on_reset(state, p, endp)) { case 0: goto s_n_llhttp__internal__n_invoke_update_finish; case 21: - goto s_n_llhttp__internal__n_pause_28; + goto s_n_llhttp__internal__n_pause_32; default: - goto s_n_llhttp__internal__n_error_110; + goto s_n_llhttp__internal__n_error_116; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } s_n_llhttp__internal__n_invoke_load_initial_message_completed: { switch (llhttp__internal__c_load_initial_message_completed(state, p, endp)) { @@ -10128,8 +10060,7 @@ static llparse_state_t llhttp__internal__run( default: goto s_n_llhttp__internal__n_invoke_update_finish; } - /* UNREACHABLE */; - abort(); + UNREACHABLE; } } diff --git a/deps/openssl/config/Dockerfile b/deps/openssl/config/Dockerfile index 5133a88b0d33e2..9929a9315ead91 100644 --- a/deps/openssl/config/Dockerfile +++ b/deps/openssl/config/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:20.04 +FROM ubuntu:22.04 VOLUME /node diff --git a/deps/openssl/openssl-cl_asm.gypi b/deps/openssl/openssl-cl_asm.gypi index cd10355c171228..2e58f0dcb094a0 100644 --- a/deps/openssl/openssl-cl_asm.gypi +++ b/deps/openssl/openssl-cl_asm.gypi @@ -8,7 +8,7 @@ 'includes': ['config/archs/linux64-s390x/asm/openssl-cl.gypi'], }, 'target_arch=="arm" and OS=="linux"', { 'includes': ['config/archs/linux-armv4/asm/openssl-cl.gypi'], - }, 'target_arch=="arm64" and OS=="linux"', { + }, 'target_arch=="arm64" and OS in "linux openharmony"', { 'includes': ['config/archs/linux-aarch64/asm/openssl-cl.gypi'], }, 'target_arch=="ia32" and OS=="freebsd"', { 'includes': ['config/archs/BSD-x86/asm/openssl-cl.gypi'], diff --git a/deps/openssl/openssl-cl_asm_avx2.gypi b/deps/openssl/openssl-cl_asm_avx2.gypi index 50b5a9c375bd8d..03056a832d0322 100644 --- a/deps/openssl/openssl-cl_asm_avx2.gypi +++ b/deps/openssl/openssl-cl_asm_avx2.gypi @@ -8,7 +8,7 @@ 'includes': ['config/archs/linux64-s390x/asm_avx2/openssl-cl.gypi'], }, 'target_arch=="arm" and OS=="linux"', { 'includes': ['config/archs/linux-armv4/asm_avx2/openssl-cl.gypi'], - }, 'target_arch=="arm64" and OS=="linux"', { + }, 'target_arch=="arm64" and OS in "linux openharmony"', { 'includes': ['config/archs/linux-aarch64/asm_avx2/openssl-cl.gypi'], }, 'target_arch=="ia32" and OS=="freebsd"', { 'includes': ['config/archs/BSD-x86/asm_avx2/openssl-cl.gypi'], diff --git a/deps/openssl/openssl-cl_no_asm.gypi b/deps/openssl/openssl-cl_no_asm.gypi index 0964fb36739b3a..c838da5cf9ea85 100644 --- a/deps/openssl/openssl-cl_no_asm.gypi +++ b/deps/openssl/openssl-cl_no_asm.gypi @@ -8,7 +8,7 @@ 'includes': ['config/archs/linux64-s390x/no-asm/openssl-cl.gypi'], }, 'target_arch=="arm" and OS in ("linux", "android")', { 'includes': ['config/archs/linux-armv4/no-asm/openssl-cl.gypi'], - }, 'target_arch=="arm64" and OS in ("linux", "android")', { + }, 'target_arch=="arm64" and OS in ("linux", "android", "openharmony")', { 'includes': ['config/archs/linux-aarch64/no-asm/openssl-cl.gypi'], }, 'target_arch=="arm64" and OS=="win"', { 'includes': ['config/archs/VC-WIN64-ARM/no-asm/openssl-cl.gypi'], diff --git a/deps/openssl/openssl-cli.gypi b/deps/openssl/openssl-cli.gypi index b4c278b4fe8f9f..ae74be9a2b17d2 100644 --- a/deps/openssl/openssl-cli.gypi +++ b/deps/openssl/openssl-cli.gypi @@ -14,7 +14,7 @@ 'link_settings': { 'libraries': ['<@(openssl_cli_libraries_win)'], }, - }, 'OS in "linux android"', { + }, 'OS in "linux android openharmony"', { 'link_settings': { 'libraries': [ '-ldl', diff --git a/deps/openssl/openssl-fips_asm.gypi b/deps/openssl/openssl-fips_asm.gypi index 631df9eb893288..633aae4b386759 100644 --- a/deps/openssl/openssl-fips_asm.gypi +++ b/deps/openssl/openssl-fips_asm.gypi @@ -8,7 +8,7 @@ 'includes': ['config/archs/linux64-s390x/asm/openssl-fips.gypi'], }, 'target_arch=="arm" and OS=="linux"', { 'includes': ['config/archs/linux-armv4/asm/openssl-fips.gypi'], - }, 'target_arch=="arm64" and OS=="linux"', { + }, 'target_arch=="arm64" and OS in "linux openharmony"', { 'includes': ['config/archs/linux-aarch64/asm/openssl-fips.gypi'], }, 'target_arch=="arm64" and OS=="mac"', { 'includes': ['config/archs/darwin64-arm64-cc/asm/openssl-fips.gypi'], diff --git a/deps/openssl/openssl-fips_asm_avx2.gypi b/deps/openssl/openssl-fips_asm_avx2.gypi index 4d63cacf29d040..74cc78c42a7b15 100644 --- a/deps/openssl/openssl-fips_asm_avx2.gypi +++ b/deps/openssl/openssl-fips_asm_avx2.gypi @@ -8,7 +8,7 @@ 'includes': ['config/archs/linux64-s390x/asm_avx2/openssl-fips.gypi'], }, 'target_arch=="arm" and OS=="linux"', { 'includes': ['config/archs/linux-armv4/asm_avx2/openssl-fips.gypi'], - }, 'target_arch=="arm64" and OS=="linux"', { + }, 'target_arch=="arm64" and OS in "linux openharmony"', { 'includes': ['config/archs/linux-aarch64/asm_avx2/openssl-fips.gypi'], }, 'target_arch=="ia32" and OS=="freebsd"', { 'includes': ['config/archs/BSD-x86/asm_avx2/openssl-fips.gypi'], diff --git a/deps/openssl/openssl-fips_no_asm.gypi b/deps/openssl/openssl-fips_no_asm.gypi index 7fdfd772abbce8..ab8074cf4397a5 100644 --- a/deps/openssl/openssl-fips_no_asm.gypi +++ b/deps/openssl/openssl-fips_no_asm.gypi @@ -9,7 +9,7 @@ 'includes': ['config/archs/linux64-s390x/no-asm/openssl-fips.gypi'], }, 'target_arch=="arm" and OS in ("linux", "android")', { 'includes': ['config/archs/linux-armv4/no-asm/openssl-fips.gypi'], - }, 'target_arch=="arm64" and OS in ("linux", "android")', { + }, 'target_arch=="arm64" and OS in ("linux", "android", "openharmony")', { 'includes': ['config/archs/linux-aarch64/no-asm/openssl-fips.gypi'], }, 'target_arch=="ia32" and OS=="freebsd"', { 'includes': ['config/archs/BSD-x86/no-asm/openssl-fips.gypi'], diff --git a/deps/openssl/openssl_asm.gypi b/deps/openssl/openssl_asm.gypi index dd7e636eb08893..51631c536bbbef 100644 --- a/deps/openssl/openssl_asm.gypi +++ b/deps/openssl/openssl_asm.gypi @@ -8,7 +8,7 @@ 'includes': ['config/archs/linux64-s390x/asm/openssl.gypi'], }, 'target_arch=="arm" and OS=="linux"', { 'includes': ['config/archs/linux-armv4/asm/openssl.gypi'], - }, 'target_arch=="arm64" and OS=="linux"', { + }, 'target_arch=="arm64" and OS in "linux openharmony"', { 'includes': ['config/archs/linux-aarch64/asm/openssl.gypi'], }, 'target_arch=="arm64" and OS=="mac"', { 'includes': ['config/archs/darwin64-arm64-cc/asm/openssl.gypi'], diff --git a/deps/openssl/openssl_asm_avx2.gypi b/deps/openssl/openssl_asm_avx2.gypi index 6a9c56d76a211a..a6e69b71524366 100644 --- a/deps/openssl/openssl_asm_avx2.gypi +++ b/deps/openssl/openssl_asm_avx2.gypi @@ -8,7 +8,7 @@ 'includes': ['config/archs/linux64-s390x/asm_avx2/openssl.gypi'], }, 'target_arch=="arm" and OS=="linux"', { 'includes': ['config/archs/linux-armv4/asm_avx2/openssl.gypi'], - }, 'target_arch=="arm64" and OS=="linux"', { + }, 'target_arch=="arm64" and OS in ("linux", "openharmony")', { 'includes': ['config/archs/linux-aarch64/asm_avx2/openssl.gypi'], }, 'target_arch=="ia32" and OS=="freebsd"', { 'includes': ['config/archs/BSD-x86/asm_avx2/openssl.gypi'], diff --git a/deps/openssl/openssl_no_asm.gypi b/deps/openssl/openssl_no_asm.gypi index 20663decabba23..8169f605d7d7f1 100644 --- a/deps/openssl/openssl_no_asm.gypi +++ b/deps/openssl/openssl_no_asm.gypi @@ -9,7 +9,7 @@ 'includes': ['config/archs/linux64-s390x/no-asm/openssl.gypi'], }, 'target_arch=="arm" and OS in ("linux", "android")', { 'includes': ['config/archs/linux-armv4/no-asm/openssl.gypi'], - }, 'target_arch=="arm64" and OS in ("linux", "android")', { + }, 'target_arch=="arm64" and OS in ("linux", "android", "openharmony")', { 'includes': ['config/archs/linux-aarch64/no-asm/openssl.gypi'], }, 'target_arch=="ia32" and OS=="freebsd"', { 'includes': ['config/archs/BSD-x86/no-asm/openssl.gypi'], diff --git a/deps/simdjson/simdjson.cpp b/deps/simdjson/simdjson.cpp index aaeca3fadde29b..d0f441b5a5401d 100644 --- a/deps/simdjson/simdjson.cpp +++ b/deps/simdjson/simdjson.cpp @@ -1,4 +1,4 @@ -/* auto-generated on 2025-02-14 16:11:36 -0500. Do not edit! */ +/* auto-generated on 2025-03-27 15:01:10 -0400. Do not edit! */ /* including simdjson.cpp: */ /* begin file simdjson.cpp */ #define SIMDJSON_SRC_SIMDJSON_CPP @@ -776,22 +776,22 @@ inline namespace literals { inline namespace string_view_literals { -constexpr std::string_view operator "" _sv( const char* str, size_t len ) noexcept // (1) +constexpr std::string_view operator ""_sv( const char* str, size_t len ) noexcept // (1) { return std::string_view{ str, len }; } -constexpr std::u16string_view operator "" _sv( const char16_t* str, size_t len ) noexcept // (2) +constexpr std::u16string_view operator ""_sv( const char16_t* str, size_t len ) noexcept // (2) { return std::u16string_view{ str, len }; } -constexpr std::u32string_view operator "" _sv( const char32_t* str, size_t len ) noexcept // (3) +constexpr std::u32string_view operator ""_sv( const char32_t* str, size_t len ) noexcept // (3) { return std::u32string_view{ str, len }; } -constexpr std::wstring_view operator "" _sv( const wchar_t* str, size_t len ) noexcept // (4) +constexpr std::wstring_view operator ""_sv( const wchar_t* str, size_t len ) noexcept // (4) { return std::wstring_view{ str, len }; } @@ -2122,22 +2122,22 @@ nssv_inline_ns namespace string_view_literals { #if nssv_CONFIG_STD_SV_OPERATOR && nssv_HAVE_STD_DEFINED_LITERALS -nssv_constexpr nonstd::sv_lite::string_view operator "" sv( const char* str, size_t len ) nssv_noexcept // (1) +nssv_constexpr nonstd::sv_lite::string_view operator ""sv( const char* str, size_t len ) nssv_noexcept // (1) { return nonstd::sv_lite::string_view{ str, len }; } -nssv_constexpr nonstd::sv_lite::u16string_view operator "" sv( const char16_t* str, size_t len ) nssv_noexcept // (2) +nssv_constexpr nonstd::sv_lite::u16string_view operator ""sv( const char16_t* str, size_t len ) nssv_noexcept // (2) { return nonstd::sv_lite::u16string_view{ str, len }; } -nssv_constexpr nonstd::sv_lite::u32string_view operator "" sv( const char32_t* str, size_t len ) nssv_noexcept // (3) +nssv_constexpr nonstd::sv_lite::u32string_view operator ""sv( const char32_t* str, size_t len ) nssv_noexcept // (3) { return nonstd::sv_lite::u32string_view{ str, len }; } -nssv_constexpr nonstd::sv_lite::wstring_view operator "" sv( const wchar_t* str, size_t len ) nssv_noexcept // (4) +nssv_constexpr nonstd::sv_lite::wstring_view operator ""sv( const wchar_t* str, size_t len ) nssv_noexcept // (4) { return nonstd::sv_lite::wstring_view{ str, len }; } @@ -2146,22 +2146,22 @@ nssv_constexpr nonstd::sv_lite::wstring_view operator "" sv( const wchar_t* str, #if nssv_CONFIG_USR_SV_OPERATOR -nssv_constexpr nonstd::sv_lite::string_view operator "" _sv( const char* str, size_t len ) nssv_noexcept // (1) +nssv_constexpr nonstd::sv_lite::string_view operator ""_sv( const char* str, size_t len ) nssv_noexcept // (1) { return nonstd::sv_lite::string_view{ str, len }; } -nssv_constexpr nonstd::sv_lite::u16string_view operator "" _sv( const char16_t* str, size_t len ) nssv_noexcept // (2) +nssv_constexpr nonstd::sv_lite::u16string_view operator ""_sv( const char16_t* str, size_t len ) nssv_noexcept // (2) { return nonstd::sv_lite::u16string_view{ str, len }; } -nssv_constexpr nonstd::sv_lite::u32string_view operator "" _sv( const char32_t* str, size_t len ) nssv_noexcept // (3) +nssv_constexpr nonstd::sv_lite::u32string_view operator ""_sv( const char32_t* str, size_t len ) nssv_noexcept // (3) { return nonstd::sv_lite::u32string_view{ str, len }; } -nssv_constexpr nonstd::sv_lite::wstring_view operator "" _sv( const wchar_t* str, size_t len ) nssv_noexcept // (4) +nssv_constexpr nonstd::sv_lite::wstring_view operator ""_sv( const wchar_t* str, size_t len ) nssv_noexcept // (4) { return nonstd::sv_lite::wstring_view{ str, len }; } @@ -2431,7 +2431,7 @@ enum error_code { SUCCESS = 0, ///< No error CAPACITY, ///< This parser can't support a document that big MEMALLOC, ///< Error allocating memory, most likely out of memory - TAPE_ERROR, ///< Something went wrong, this is a generic error + TAPE_ERROR, ///< Something went wrong, this is a generic error. Fatal/unrecoverable error. DEPTH_ERROR, ///< Your document exceeds the user-specified depth limitation STRING_ERROR, ///< Problem while parsing a string T_ATOM_ERROR, ///< Problem while parsing an atom starting with the letter 't' @@ -2456,13 +2456,21 @@ enum error_code { PARSER_IN_USE, ///< parser is already in use. OUT_OF_ORDER_ITERATION, ///< tried to iterate an array or object out of order (checked when SIMDJSON_DEVELOPMENT_CHECKS=1) INSUFFICIENT_PADDING, ///< The JSON doesn't have enough padding for simdjson to safely parse it. - INCOMPLETE_ARRAY_OR_OBJECT, ///< The document ends early. + INCOMPLETE_ARRAY_OR_OBJECT, ///< The document ends early. Fatal/unrecoverable error. SCALAR_DOCUMENT_AS_VALUE, ///< A scalar document is treated as a value. OUT_OF_BOUNDS, ///< Attempted to access location outside of document. TRAILING_CONTENT, ///< Unexpected trailing content in the JSON input NUM_ERROR_CODES }; +/** + * Some errors are fatal and invalidate the document. This function returns true if the + * error is fatal. It returns true for TAPE_ERROR and INCOMPLETE_ARRAY_OR_OBJECT. + * Once a fatal error is encountered, the on-demand document is no longer valid and + * processing should stop. + */ + inline bool is_fatal(error_code error) noexcept; + /** * It is the convention throughout the code that the macro SIMDJSON_DEVELOPMENT_CHECKS determines whether * we check for OUT_OF_ORDER_ITERATION. The logic behind it is that these errors only occurs when the code @@ -2765,14 +2773,30 @@ SIMDJSON_IMPL_CONCEPT(op_append, operator+=) #undef SIMDJSON_IMPL_CONCEPT } // namespace details + +template +concept string_view_like = std::is_convertible_v && + !std::is_convertible_v; + +template +concept constructible_from_string_view = std::is_constructible_v + && !std::is_same_v + && std::is_default_constructible_v; + +template +concept string_view_keyed_map = string_view_like + && requires(std::remove_cvref_t& m, typename M::key_type sv, typename M::mapped_type v) { + { m.emplace(sv, v) } -> std::same_as>; +}; + /// Check if T is a container that we can append to, including: /// std::vector, std::deque, std::list, std::string, ... template concept appendable_containers = - details::supports_emplace_back || details::supports_emplace || + (details::supports_emplace_back || details::supports_emplace || details::supports_push_back || details::supports_push || details::supports_add || details::supports_append || - details::supports_insert; + details::supports_insert) && !string_view_keyed_map; /// Insert into the container however possible template @@ -2840,6 +2864,8 @@ concept optional_type = requires(std::remove_cvref_t obj) { { static_cast(obj) } -> std::same_as; // convertible to bool }; + + } // namespace concepts } // namespace simdjson #endif // SIMDJSON_SUPPORTS_DESERIALIZATION @@ -4511,6 +4537,11 @@ extern SIMDJSON_DLLIMPORTEXPORT const uint32_t digit_to_val32[886]; #include namespace simdjson { + +inline bool is_fatal(error_code error) noexcept { + return error == TAPE_ERROR || error == INCOMPLETE_ARRAY_OR_OBJECT; +} + namespace internal { // We store the error code so we can validate the error message is associated with the right code struct error_code_info { @@ -4696,7 +4727,7 @@ namespace internal { { SUCCESS, "SUCCESS: No error" }, { CAPACITY, "CAPACITY: This parser can't support a document that big" }, { MEMALLOC, "MEMALLOC: Error allocating memory, we're most likely out of memory" }, - { TAPE_ERROR, "TAPE_ERROR: The JSON document has an improper structure: missing or superfluous commas, braces, missing keys, etc." }, + { TAPE_ERROR, "TAPE_ERROR: The JSON document has an improper structure: missing or superfluous commas, braces, missing keys, etc. This is a fatal and unrecoverable error." }, { DEPTH_ERROR, "DEPTH_ERROR: The JSON document was too deep (too many nested objects and arrays)" }, { STRING_ERROR, "STRING_ERROR: Problem while parsing a string" }, { T_ATOM_ERROR, "T_ATOM_ERROR: Problem while parsing an atom starting with the letter 't'" }, @@ -4721,7 +4752,7 @@ namespace internal { { PARSER_IN_USE, "PARSER_IN_USE: Cannot parse a new document while a document is still in use." }, { OUT_OF_ORDER_ITERATION, "OUT_OF_ORDER_ITERATION: Objects and arrays can only be iterated when they are first encountered." }, { INSUFFICIENT_PADDING, "INSUFFICIENT_PADDING: simdjson requires the input JSON string to have at least SIMDJSON_PADDING extra bytes allocated, beyond the string's length. Consider using the simdjson::padded_string class if needed." }, - { INCOMPLETE_ARRAY_OR_OBJECT, "INCOMPLETE_ARRAY_OR_OBJECT: JSON document ended early in the middle of an object or array." }, + { INCOMPLETE_ARRAY_OR_OBJECT, "INCOMPLETE_ARRAY_OR_OBJECT: JSON document ended early in the middle of an object or array. This is a fatal and unrecoverable error." }, { SCALAR_DOCUMENT_AS_VALUE, "SCALAR_DOCUMENT_AS_VALUE: A JSON document made of a scalar (number, Boolean, null or string) is treated as a value. Use get_bool(), get_double(), etc. on the document instead. "}, { OUT_OF_BOUNDS, "OUT_OF_BOUNDS: Attempt to access location outside of document."}, { TRAILING_CONTENT, "TRAILING_CONTENT: Unexpected trailing content in the JSON input."} @@ -6787,7 +6818,7 @@ class document { * The memory allocation is strict: you * can you use this function to increase * or lower the amount of allocated memory. - * Passsing zero clears the memory. + * Passing zero clears the memory. */ error_code allocate(size_t len) noexcept; /** @private Capacity in bytes, in terms @@ -9185,7 +9216,7 @@ simdjson_inline bool compute_float_64(int64_t power, uint64_t i, bool negative, // floor(log(5**power)/log(2)) // // Note that this is not magic: 152170/(1<<16) is - // approximatively equal to log(5)/log(2). + // approximately equal to log(5)/log(2). // The 1<<16 value is a power of two; we could use a // larger power of 2 if we wanted to. // @@ -15545,7 +15576,7 @@ simdjson_inline bool compute_float_64(int64_t power, uint64_t i, bool negative, // floor(log(5**power)/log(2)) // // Note that this is not magic: 152170/(1<<16) is - // approximatively equal to log(5)/log(2). + // approximately equal to log(5)/log(2). // The 1<<16 value is a power of two; we could use a // larger power of 2 if we wanted to. // @@ -21769,7 +21800,7 @@ simdjson_inline bool compute_float_64(int64_t power, uint64_t i, bool negative, // floor(log(5**power)/log(2)) // // Note that this is not magic: 152170/(1<<16) is - // approximatively equal to log(5)/log(2). + // approximately equal to log(5)/log(2). // The 1<<16 value is a power of two; we could use a // larger power of 2 if we wanted to. // @@ -28149,7 +28180,7 @@ simdjson_inline bool compute_float_64(int64_t power, uint64_t i, bool negative, // floor(log(5**power)/log(2)) // // Note that this is not magic: 152170/(1<<16) is - // approximatively equal to log(5)/log(2). + // approximately equal to log(5)/log(2). // The 1<<16 value is a power of two; we could use a // larger power of 2 if we wanted to. // @@ -34891,7 +34922,7 @@ simdjson_inline bool compute_float_64(int64_t power, uint64_t i, bool negative, // floor(log(5**power)/log(2)) // // Note that this is not magic: 152170/(1<<16) is - // approximatively equal to log(5)/log(2). + // approximately equal to log(5)/log(2). // The 1<<16 value is a power of two; we could use a // larger power of 2 if we wanted to. // @@ -41457,7 +41488,7 @@ simdjson_inline bool compute_float_64(int64_t power, uint64_t i, bool negative, // floor(log(5**power)/log(2)) // // Note that this is not magic: 152170/(1<<16) is - // approximatively equal to log(5)/log(2). + // approximately equal to log(5)/log(2). // The 1<<16 value is a power of two; we could use a // larger power of 2 if we wanted to. // @@ -47468,7 +47499,7 @@ simdjson_inline bool compute_float_64(int64_t power, uint64_t i, bool negative, // floor(log(5**power)/log(2)) // // Note that this is not magic: 152170/(1<<16) is - // approximatively equal to log(5)/log(2). + // approximately equal to log(5)/log(2). // The 1<<16 value is a power of two; we could use a // larger power of 2 if we wanted to. // @@ -53078,7 +53109,7 @@ simdjson_inline bool compute_float_64(int64_t power, uint64_t i, bool negative, // floor(log(5**power)/log(2)) // // Note that this is not magic: 152170/(1<<16) is - // approximatively equal to log(5)/log(2). + // approximately equal to log(5)/log(2). // The 1<<16 value is a power of two; we could use a // larger power of 2 if we wanted to. // diff --git a/deps/simdjson/simdjson.h b/deps/simdjson/simdjson.h index c1535ee81300b9..a0d449975224a3 100644 --- a/deps/simdjson/simdjson.h +++ b/deps/simdjson/simdjson.h @@ -1,4 +1,4 @@ -/* auto-generated on 2025-02-14 16:11:36 -0500. Do not edit! */ +/* auto-generated on 2025-03-27 15:01:10 -0400. Do not edit! */ /* including simdjson.h: */ /* begin file simdjson.h */ #ifndef SIMDJSON_H @@ -796,22 +796,22 @@ inline namespace literals { inline namespace string_view_literals { -constexpr std::string_view operator "" _sv( const char* str, size_t len ) noexcept // (1) +constexpr std::string_view operator ""_sv( const char* str, size_t len ) noexcept // (1) { return std::string_view{ str, len }; } -constexpr std::u16string_view operator "" _sv( const char16_t* str, size_t len ) noexcept // (2) +constexpr std::u16string_view operator ""_sv( const char16_t* str, size_t len ) noexcept // (2) { return std::u16string_view{ str, len }; } -constexpr std::u32string_view operator "" _sv( const char32_t* str, size_t len ) noexcept // (3) +constexpr std::u32string_view operator ""_sv( const char32_t* str, size_t len ) noexcept // (3) { return std::u32string_view{ str, len }; } -constexpr std::wstring_view operator "" _sv( const wchar_t* str, size_t len ) noexcept // (4) +constexpr std::wstring_view operator ""_sv( const wchar_t* str, size_t len ) noexcept // (4) { return std::wstring_view{ str, len }; } @@ -2142,22 +2142,22 @@ nssv_inline_ns namespace string_view_literals { #if nssv_CONFIG_STD_SV_OPERATOR && nssv_HAVE_STD_DEFINED_LITERALS -nssv_constexpr nonstd::sv_lite::string_view operator "" sv( const char* str, size_t len ) nssv_noexcept // (1) +nssv_constexpr nonstd::sv_lite::string_view operator ""sv( const char* str, size_t len ) nssv_noexcept // (1) { return nonstd::sv_lite::string_view{ str, len }; } -nssv_constexpr nonstd::sv_lite::u16string_view operator "" sv( const char16_t* str, size_t len ) nssv_noexcept // (2) +nssv_constexpr nonstd::sv_lite::u16string_view operator ""sv( const char16_t* str, size_t len ) nssv_noexcept // (2) { return nonstd::sv_lite::u16string_view{ str, len }; } -nssv_constexpr nonstd::sv_lite::u32string_view operator "" sv( const char32_t* str, size_t len ) nssv_noexcept // (3) +nssv_constexpr nonstd::sv_lite::u32string_view operator ""sv( const char32_t* str, size_t len ) nssv_noexcept // (3) { return nonstd::sv_lite::u32string_view{ str, len }; } -nssv_constexpr nonstd::sv_lite::wstring_view operator "" sv( const wchar_t* str, size_t len ) nssv_noexcept // (4) +nssv_constexpr nonstd::sv_lite::wstring_view operator ""sv( const wchar_t* str, size_t len ) nssv_noexcept // (4) { return nonstd::sv_lite::wstring_view{ str, len }; } @@ -2166,22 +2166,22 @@ nssv_constexpr nonstd::sv_lite::wstring_view operator "" sv( const wchar_t* str, #if nssv_CONFIG_USR_SV_OPERATOR -nssv_constexpr nonstd::sv_lite::string_view operator "" _sv( const char* str, size_t len ) nssv_noexcept // (1) +nssv_constexpr nonstd::sv_lite::string_view operator ""_sv( const char* str, size_t len ) nssv_noexcept // (1) { return nonstd::sv_lite::string_view{ str, len }; } -nssv_constexpr nonstd::sv_lite::u16string_view operator "" _sv( const char16_t* str, size_t len ) nssv_noexcept // (2) +nssv_constexpr nonstd::sv_lite::u16string_view operator ""_sv( const char16_t* str, size_t len ) nssv_noexcept // (2) { return nonstd::sv_lite::u16string_view{ str, len }; } -nssv_constexpr nonstd::sv_lite::u32string_view operator "" _sv( const char32_t* str, size_t len ) nssv_noexcept // (3) +nssv_constexpr nonstd::sv_lite::u32string_view operator ""_sv( const char32_t* str, size_t len ) nssv_noexcept // (3) { return nonstd::sv_lite::u32string_view{ str, len }; } -nssv_constexpr nonstd::sv_lite::wstring_view operator "" _sv( const wchar_t* str, size_t len ) nssv_noexcept // (4) +nssv_constexpr nonstd::sv_lite::wstring_view operator ""_sv( const wchar_t* str, size_t len ) nssv_noexcept // (4) { return nonstd::sv_lite::wstring_view{ str, len }; } @@ -2437,7 +2437,7 @@ namespace std { #define SIMDJSON_SIMDJSON_VERSION_H /** The version of simdjson being used (major.minor.revision) */ -#define SIMDJSON_VERSION "3.12.2" +#define SIMDJSON_VERSION "3.12.3" namespace simdjson { enum { @@ -2452,7 +2452,7 @@ enum { /** * The revision (major.minor.REVISION) of simdjson being used. */ - SIMDJSON_VERSION_REVISION = 2 + SIMDJSON_VERSION_REVISION = 3 }; } // namespace simdjson @@ -2494,7 +2494,7 @@ enum error_code { SUCCESS = 0, ///< No error CAPACITY, ///< This parser can't support a document that big MEMALLOC, ///< Error allocating memory, most likely out of memory - TAPE_ERROR, ///< Something went wrong, this is a generic error + TAPE_ERROR, ///< Something went wrong, this is a generic error. Fatal/unrecoverable error. DEPTH_ERROR, ///< Your document exceeds the user-specified depth limitation STRING_ERROR, ///< Problem while parsing a string T_ATOM_ERROR, ///< Problem while parsing an atom starting with the letter 't' @@ -2519,13 +2519,21 @@ enum error_code { PARSER_IN_USE, ///< parser is already in use. OUT_OF_ORDER_ITERATION, ///< tried to iterate an array or object out of order (checked when SIMDJSON_DEVELOPMENT_CHECKS=1) INSUFFICIENT_PADDING, ///< The JSON doesn't have enough padding for simdjson to safely parse it. - INCOMPLETE_ARRAY_OR_OBJECT, ///< The document ends early. + INCOMPLETE_ARRAY_OR_OBJECT, ///< The document ends early. Fatal/unrecoverable error. SCALAR_DOCUMENT_AS_VALUE, ///< A scalar document is treated as a value. OUT_OF_BOUNDS, ///< Attempted to access location outside of document. TRAILING_CONTENT, ///< Unexpected trailing content in the JSON input NUM_ERROR_CODES }; +/** + * Some errors are fatal and invalidate the document. This function returns true if the + * error is fatal. It returns true for TAPE_ERROR and INCOMPLETE_ARRAY_OR_OBJECT. + * Once a fatal error is encountered, the on-demand document is no longer valid and + * processing should stop. + */ + inline bool is_fatal(error_code error) noexcept; + /** * It is the convention throughout the code that the macro SIMDJSON_DEVELOPMENT_CHECKS determines whether * we check for OUT_OF_ORDER_ITERATION. The logic behind it is that these errors only occurs when the code @@ -2828,14 +2836,30 @@ SIMDJSON_IMPL_CONCEPT(op_append, operator+=) #undef SIMDJSON_IMPL_CONCEPT } // namespace details + +template +concept string_view_like = std::is_convertible_v && + !std::is_convertible_v; + +template +concept constructible_from_string_view = std::is_constructible_v + && !std::is_same_v + && std::is_default_constructible_v; + +template +concept string_view_keyed_map = string_view_like + && requires(std::remove_cvref_t& m, typename M::key_type sv, typename M::mapped_type v) { + { m.emplace(sv, v) } -> std::same_as>; +}; + /// Check if T is a container that we can append to, including: /// std::vector, std::deque, std::list, std::string, ... template concept appendable_containers = - details::supports_emplace_back || details::supports_emplace || + (details::supports_emplace_back || details::supports_emplace || details::supports_push_back || details::supports_push || details::supports_add || details::supports_append || - details::supports_insert; + details::supports_insert) && !string_view_keyed_map; /// Insert into the container however possible template @@ -2903,6 +2927,8 @@ concept optional_type = requires(std::remove_cvref_t obj) { { static_cast(obj) } -> std::same_as; // convertible to bool }; + + } // namespace concepts } // namespace simdjson #endif // SIMDJSON_SUPPORTS_DESERIALIZATION @@ -2970,6 +2996,11 @@ enum class tape_type; #include namespace simdjson { + +inline bool is_fatal(error_code error) noexcept { + return error == TAPE_ERROR || error == INCOMPLETE_ARRAY_OR_OBJECT; +} + namespace internal { // We store the error code so we can validate the error message is associated with the right code struct error_code_info { @@ -4656,7 +4687,7 @@ class document { * The memory allocation is strict: you * can you use this function to increase * or lower the amount of allocated memory. - * Passsing zero clears the memory. + * Passing zero clears the memory. */ error_code allocate(size_t len) noexcept; /** @private Capacity in bytes, in terms @@ -5013,7 +5044,7 @@ class parser { * arrays or objects) MUST be separated with whitespace. * * The documents must not exceed batch_size bytes (by default 1MB) or they will fail to parse. - * Setting batch_size to excessively large or excesively small values may impact negatively the + * Setting batch_size to excessively large or excessively small values may impact negatively the * performance. * * ### Error Handling @@ -5107,7 +5138,7 @@ class parser { * arrays or objects) MUST be separated with whitespace. * * The documents must not exceed batch_size bytes (by default 1MB) or they will fail to parse. - * Setting batch_size to excessively large or excesively small values may impact negatively the + * Setting batch_size to excessively large or excessively small values may impact negatively the * performance. * * ### Error Handling @@ -11599,7 +11630,7 @@ simdjson_inline bool compute_float_64(int64_t power, uint64_t i, bool negative, // floor(log(5**power)/log(2)) // // Note that this is not magic: 152170/(1<<16) is - // approximatively equal to log(5)/log(2). + // approximately equal to log(5)/log(2). // The 1<<16 value is a power of two; we could use a // larger power of 2 if we wanted to. // @@ -13707,7 +13738,7 @@ simdjson_inline bool compute_float_64(int64_t power, uint64_t i, bool negative, // floor(log(5**power)/log(2)) // // Note that this is not magic: 152170/(1<<16) is - // approximatively equal to log(5)/log(2). + // approximately equal to log(5)/log(2). // The 1<<16 value is a power of two; we could use a // larger power of 2 if we wanted to. // @@ -16307,7 +16338,7 @@ simdjson_inline bool compute_float_64(int64_t power, uint64_t i, bool negative, // floor(log(5**power)/log(2)) // // Note that this is not magic: 152170/(1<<16) is - // approximatively equal to log(5)/log(2). + // approximately equal to log(5)/log(2). // The 1<<16 value is a power of two; we could use a // larger power of 2 if we wanted to. // @@ -18904,7 +18935,7 @@ simdjson_inline bool compute_float_64(int64_t power, uint64_t i, bool negative, // floor(log(5**power)/log(2)) // // Note that this is not magic: 152170/(1<<16) is - // approximatively equal to log(5)/log(2). + // approximately equal to log(5)/log(2). // The 1<<16 value is a power of two; we could use a // larger power of 2 if we wanted to. // @@ -21618,7 +21649,7 @@ simdjson_inline bool compute_float_64(int64_t power, uint64_t i, bool negative, // floor(log(5**power)/log(2)) // // Note that this is not magic: 152170/(1<<16) is - // approximatively equal to log(5)/log(2). + // approximately equal to log(5)/log(2). // The 1<<16 value is a power of two; we could use a // larger power of 2 if we wanted to. // @@ -24649,7 +24680,7 @@ simdjson_inline bool compute_float_64(int64_t power, uint64_t i, bool negative, // floor(log(5**power)/log(2)) // // Note that this is not magic: 152170/(1<<16) is - // approximatively equal to log(5)/log(2). + // approximately equal to log(5)/log(2). // The 1<<16 value is a power of two; we could use a // larger power of 2 if we wanted to. // @@ -27157,7 +27188,7 @@ simdjson_inline bool compute_float_64(int64_t power, uint64_t i, bool negative, // floor(log(5**power)/log(2)) // // Note that this is not magic: 152170/(1<<16) is - // approximatively equal to log(5)/log(2). + // approximately equal to log(5)/log(2). // The 1<<16 value is a power of two; we could use a // larger power of 2 if we wanted to. // @@ -29678,7 +29709,7 @@ simdjson_inline bool compute_float_64(int64_t power, uint64_t i, bool negative, // floor(log(5**power)/log(2)) // // Note that this is not magic: 152170/(1<<16) is - // approximatively equal to log(5)/log(2). + // approximately equal to log(5)/log(2). // The 1<<16 value is a power of two; we could use a // larger power of 2 if we wanted to. // @@ -32147,7 +32178,8 @@ class value_iterator { * * @returns Whether the object had any fields (returns false for empty). * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent* - * array or object is incomplete). + * array or object is incomplete). An INCOMPLETE_ARRAY_OR_OBJECT is an unrecoverable error that + * invalidates the document. */ simdjson_warn_unused simdjson_inline simdjson_result started_object() noexcept; /** @@ -32157,7 +32189,8 @@ class value_iterator { * * @returns Whether the object had any fields (returns false for empty). * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent* - * array or object is incomplete). + * array or object is incomplete). An INCOMPLETE_ARRAY_OR_OBJECT is an unrecoverable error that + * invalidates the document. */ simdjson_warn_unused simdjson_inline simdjson_result started_root_object() noexcept; @@ -32279,7 +32312,8 @@ class value_iterator { * * @returns Whether the array had any elements (returns false for empty). * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent* - * array or object is incomplete). + * array or object is incomplete). An INCOMPLETE_ARRAY_OR_OBJECT is an unrecoverable error that + * invalidates the document. */ simdjson_warn_unused simdjson_inline simdjson_result started_array() noexcept; /** @@ -32289,7 +32323,8 @@ class value_iterator { * * @returns Whether the array had any elements (returns false for empty). * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent* - * array or object is incomplete). + * array or object is incomplete). An INCOMPLETE_ARRAY_OR_OBJECT is an unrecoverable error that + * invalidates the document. */ simdjson_warn_unused simdjson_inline simdjson_result started_root_array() noexcept; @@ -32587,22 +32622,28 @@ class value { noexcept #endif { -#if SIMDJSON_SUPPORTS_DESERIALIZATION - if constexpr (custom_deserializable) { + #if SIMDJSON_SUPPORTS_DESERIALIZATION + if constexpr (custom_deserializable) { return deserialize(*this, out); - } else { -#endif // SIMDJSON_SUPPORTS_DESERIALIZATION - // Unless the simdjson library or the user provides an inline implementation, calling this method should - // immediately fail. - static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. " - "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " - "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), " - " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template." - " You may also add support for custom types, see our documentation."); - static_cast(out); // to get rid of unused errors - return UNINITIALIZED; -#if SIMDJSON_SUPPORTS_DESERIALIZATION - } + } else { + static_assert(!sizeof(T), "The get method with type T is not implemented by the simdjson library. " + "And you do not seem to have added support for it. Indeed, we have that " + "simdjson::custom_deserializable is false and the type T is not a default type " + "such as ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " + "int64_t, double, or bool."); + static_cast(out); // to get rid of unused errors + return UNINITIALIZED; + } +#else // SIMDJSON_SUPPORTS_DESERIALIZATION + // Unless the simdjson library or the user provides an inline implementation, calling this method should + // immediately fail. + static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. " + "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " + "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), " + " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template." + " You may also add support for custom types, see our documentation."); + static_cast(out); // to get rid of unused errors + return UNINITIALIZED; #endif } @@ -35237,20 +35278,27 @@ class document { if constexpr (custom_deserializable) { return deserialize(*this, out); } else { -#endif // SIMDJSON_SUPPORTS_DESERIALIZATION - // Unless the simdjson library or the user provides an inline implementation, calling this method should - // immediately fail. - static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. " - "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " - "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), " - " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template." - " You may also add support for custom types, see our documentation."); + static_assert(!sizeof(T), "The get method with type T is not implemented by the simdjson library. " + "And you do not seem to have added support for it. Indeed, we have that " + "simdjson::custom_deserializable is false and the type T is not a default type " + "such as ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " + "int64_t, double, or bool."); static_cast(out); // to get rid of unused errors return UNINITIALIZED; -#if SIMDJSON_SUPPORTS_DESERIALIZATION } -#endif +#else // SIMDJSON_SUPPORTS_DESERIALIZATION + // Unless the simdjson library or the user provides an inline implementation, calling this method should + // immediately fail. + static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. " + "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " + "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), " + " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template." + " You may also add support for custom types, see our documentation."); + static_cast(out); // to get rid of unused errors + return UNINITIALIZED; +#endif // SIMDJSON_SUPPORTS_DESERIALIZATION } + /** @overload template error_code get(T &out) & noexcept */ template simdjson_deprecated simdjson_inline error_code get(T &out) && noexcept; @@ -35812,20 +35860,27 @@ class document_reference { if constexpr (custom_deserializable) { return deserialize(*this, out); } else { -#endif // SIMDJSON_SUPPORTS_DESERIALIZATION - // Unless the simdjson library or the user provides an inline implementation, calling this method should - // immediately fail. - static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. " - "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " - "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), " - " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template." - " You may also add support for custom types, see our documentation."); + static_assert(!sizeof(T), "The get method with type T is not implemented by the simdjson library. " + "And you do not seem to have added support for it. Indeed, we have that " + "simdjson::custom_deserializable is false and the type T is not a default type " + "such as ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " + "int64_t, double, or bool."); static_cast(out); // to get rid of unused errors return UNINITIALIZED; -#if SIMDJSON_SUPPORTS_DESERIALIZATION } -#endif +#else // SIMDJSON_SUPPORTS_DESERIALIZATION + // Unless the simdjson library or the user provides an inline implementation, calling this method should + // immediately fail. + static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. " + "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " + "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), " + " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template." + " You may also add support for custom types, see our documentation."); + static_cast(out); // to get rid of unused errors + return UNINITIALIZED; +#endif // SIMDJSON_SUPPORTS_DESERIALIZATION } + /** @overload template error_code get(T &out) & noexcept */ template simdjson_inline error_code get(T &out) && noexcept; simdjson_inline simdjson_result raw_json() noexcept; @@ -37000,6 +37055,16 @@ error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept { return SUCCESS; } +template + requires(!require_custom_serialization) +error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(std::is_nothrow_constructible_v) { + std::string_view str; + SIMDJSON_TRY(val.get_string().get(str)); + out = T{str}; + return SUCCESS; +} + + /** * STL containers have several constructors including one that takes a single * size argument. Thus, some compilers (Visual Studio) will not be able to @@ -37045,6 +37110,39 @@ error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) { } +/** + * We want to support std::map and std::unordered_map but only for + * string-keyed types. + */ + template + requires(!require_custom_serialization) +error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) { + using value_type = typename std::remove_cvref_t::mapped_type; + static_assert( + deserializable, + "The specified value type inside the container must itself be deserializable"); + static_assert( + std::is_default_constructible_v, + "The specified value type inside the container must default constructible."); + arm64::ondemand::object obj; + SIMDJSON_TRY(val.get_object().get(obj)); + for (auto field : obj) { + std::string_view key; + SIMDJSON_TRY(field.unescaped_key().get(key)); + value_type this_value; + SIMDJSON_TRY(field.value().get().get(this_value)); + [[maybe_unused]] std::pair result = out.emplace(key, this_value); + // unclear what to do if the key already exists + // if (result.second == false) { + // // key already exists + // } + } + (void)out; + return SUCCESS; +} + + + /** * This CPO (Customization Point Object) will help deserialize into @@ -42269,19 +42367,23 @@ simdjson_warn_unused simdjson_inline simdjson_result value_iterator::get } return result; } + simdjson_warn_unused simdjson_inline simdjson_result value_iterator::get_root_bool(bool check_trailing) noexcept { auto max_len = peek_root_length(); auto json = peek_root_scalar("bool"); - uint8_t tmpbuf[5+1+1]; // +1 for null termination - tmpbuf[5+1] = '\0'; // make sure that buffer is always null terminated. - if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 5+1)) { return incorrect_type_error("Not a boolean"); } - auto result = parse_bool(tmpbuf); - if(result.error() == SUCCESS) { - if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; } - advance_root_scalar("bool"); - } - return result; + // We have a boolean if we have either "true" or "false" and the next character is either + // a structural character or whitespace. We also check that the length is correct: + // "true" and "false" are 4 and 5 characters long, respectively. + bool value_true = (max_len >= 4 && !atomparsing::str4ncmp(json, "true") && + (max_len == 4 || jsoncharutils::is_structural_or_whitespace(json[4]))); + bool value_false = (max_len >= 5 && !atomparsing::str4ncmp(json, "false") && + (max_len == 5 || jsoncharutils::is_structural_or_whitespace(json[5]))); + if(value_true == false && value_false == false) { return incorrect_type_error("Not a boolean"); } + if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; } + advance_root_scalar("bool"); + return value_true; } + simdjson_inline simdjson_result value_iterator::is_root_null(bool check_trailing) noexcept { auto max_len = peek_root_length(); auto json = peek_root_scalar("null"); @@ -43123,7 +43225,8 @@ class value_iterator { * * @returns Whether the object had any fields (returns false for empty). * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent* - * array or object is incomplete). + * array or object is incomplete). An INCOMPLETE_ARRAY_OR_OBJECT is an unrecoverable error that + * invalidates the document. */ simdjson_warn_unused simdjson_inline simdjson_result started_object() noexcept; /** @@ -43133,7 +43236,8 @@ class value_iterator { * * @returns Whether the object had any fields (returns false for empty). * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent* - * array or object is incomplete). + * array or object is incomplete). An INCOMPLETE_ARRAY_OR_OBJECT is an unrecoverable error that + * invalidates the document. */ simdjson_warn_unused simdjson_inline simdjson_result started_root_object() noexcept; @@ -43255,7 +43359,8 @@ class value_iterator { * * @returns Whether the array had any elements (returns false for empty). * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent* - * array or object is incomplete). + * array or object is incomplete). An INCOMPLETE_ARRAY_OR_OBJECT is an unrecoverable error that + * invalidates the document. */ simdjson_warn_unused simdjson_inline simdjson_result started_array() noexcept; /** @@ -43265,7 +43370,8 @@ class value_iterator { * * @returns Whether the array had any elements (returns false for empty). * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent* - * array or object is incomplete). + * array or object is incomplete). An INCOMPLETE_ARRAY_OR_OBJECT is an unrecoverable error that + * invalidates the document. */ simdjson_warn_unused simdjson_inline simdjson_result started_root_array() noexcept; @@ -43563,22 +43669,28 @@ class value { noexcept #endif { -#if SIMDJSON_SUPPORTS_DESERIALIZATION - if constexpr (custom_deserializable) { + #if SIMDJSON_SUPPORTS_DESERIALIZATION + if constexpr (custom_deserializable) { return deserialize(*this, out); - } else { -#endif // SIMDJSON_SUPPORTS_DESERIALIZATION - // Unless the simdjson library or the user provides an inline implementation, calling this method should - // immediately fail. - static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. " - "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " - "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), " - " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template." - " You may also add support for custom types, see our documentation."); - static_cast(out); // to get rid of unused errors - return UNINITIALIZED; -#if SIMDJSON_SUPPORTS_DESERIALIZATION - } + } else { + static_assert(!sizeof(T), "The get method with type T is not implemented by the simdjson library. " + "And you do not seem to have added support for it. Indeed, we have that " + "simdjson::custom_deserializable is false and the type T is not a default type " + "such as ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " + "int64_t, double, or bool."); + static_cast(out); // to get rid of unused errors + return UNINITIALIZED; + } +#else // SIMDJSON_SUPPORTS_DESERIALIZATION + // Unless the simdjson library or the user provides an inline implementation, calling this method should + // immediately fail. + static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. " + "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " + "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), " + " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template." + " You may also add support for custom types, see our documentation."); + static_cast(out); // to get rid of unused errors + return UNINITIALIZED; #endif } @@ -46213,20 +46325,27 @@ class document { if constexpr (custom_deserializable) { return deserialize(*this, out); } else { -#endif // SIMDJSON_SUPPORTS_DESERIALIZATION - // Unless the simdjson library or the user provides an inline implementation, calling this method should - // immediately fail. - static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. " - "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " - "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), " - " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template." - " You may also add support for custom types, see our documentation."); + static_assert(!sizeof(T), "The get method with type T is not implemented by the simdjson library. " + "And you do not seem to have added support for it. Indeed, we have that " + "simdjson::custom_deserializable is false and the type T is not a default type " + "such as ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " + "int64_t, double, or bool."); static_cast(out); // to get rid of unused errors return UNINITIALIZED; -#if SIMDJSON_SUPPORTS_DESERIALIZATION } -#endif +#else // SIMDJSON_SUPPORTS_DESERIALIZATION + // Unless the simdjson library or the user provides an inline implementation, calling this method should + // immediately fail. + static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. " + "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " + "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), " + " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template." + " You may also add support for custom types, see our documentation."); + static_cast(out); // to get rid of unused errors + return UNINITIALIZED; +#endif // SIMDJSON_SUPPORTS_DESERIALIZATION } + /** @overload template error_code get(T &out) & noexcept */ template simdjson_deprecated simdjson_inline error_code get(T &out) && noexcept; @@ -46788,20 +46907,27 @@ class document_reference { if constexpr (custom_deserializable) { return deserialize(*this, out); } else { -#endif // SIMDJSON_SUPPORTS_DESERIALIZATION - // Unless the simdjson library or the user provides an inline implementation, calling this method should - // immediately fail. - static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. " - "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " - "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), " - " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template." - " You may also add support for custom types, see our documentation."); + static_assert(!sizeof(T), "The get method with type T is not implemented by the simdjson library. " + "And you do not seem to have added support for it. Indeed, we have that " + "simdjson::custom_deserializable is false and the type T is not a default type " + "such as ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " + "int64_t, double, or bool."); static_cast(out); // to get rid of unused errors return UNINITIALIZED; -#if SIMDJSON_SUPPORTS_DESERIALIZATION } -#endif +#else // SIMDJSON_SUPPORTS_DESERIALIZATION + // Unless the simdjson library or the user provides an inline implementation, calling this method should + // immediately fail. + static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. " + "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " + "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), " + " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template." + " You may also add support for custom types, see our documentation."); + static_cast(out); // to get rid of unused errors + return UNINITIALIZED; +#endif // SIMDJSON_SUPPORTS_DESERIALIZATION } + /** @overload template error_code get(T &out) & noexcept */ template simdjson_inline error_code get(T &out) && noexcept; simdjson_inline simdjson_result raw_json() noexcept; @@ -47976,6 +48102,16 @@ error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept { return SUCCESS; } +template + requires(!require_custom_serialization) +error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(std::is_nothrow_constructible_v) { + std::string_view str; + SIMDJSON_TRY(val.get_string().get(str)); + out = T{str}; + return SUCCESS; +} + + /** * STL containers have several constructors including one that takes a single * size argument. Thus, some compilers (Visual Studio) will not be able to @@ -48021,6 +48157,39 @@ error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) { } +/** + * We want to support std::map and std::unordered_map but only for + * string-keyed types. + */ + template + requires(!require_custom_serialization) +error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) { + using value_type = typename std::remove_cvref_t::mapped_type; + static_assert( + deserializable, + "The specified value type inside the container must itself be deserializable"); + static_assert( + std::is_default_constructible_v, + "The specified value type inside the container must default constructible."); + fallback::ondemand::object obj; + SIMDJSON_TRY(val.get_object().get(obj)); + for (auto field : obj) { + std::string_view key; + SIMDJSON_TRY(field.unescaped_key().get(key)); + value_type this_value; + SIMDJSON_TRY(field.value().get().get(this_value)); + [[maybe_unused]] std::pair result = out.emplace(key, this_value); + // unclear what to do if the key already exists + // if (result.second == false) { + // // key already exists + // } + } + (void)out; + return SUCCESS; +} + + + /** * This CPO (Customization Point Object) will help deserialize into @@ -53245,19 +53414,23 @@ simdjson_warn_unused simdjson_inline simdjson_result value_iterator::get } return result; } + simdjson_warn_unused simdjson_inline simdjson_result value_iterator::get_root_bool(bool check_trailing) noexcept { auto max_len = peek_root_length(); auto json = peek_root_scalar("bool"); - uint8_t tmpbuf[5+1+1]; // +1 for null termination - tmpbuf[5+1] = '\0'; // make sure that buffer is always null terminated. - if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 5+1)) { return incorrect_type_error("Not a boolean"); } - auto result = parse_bool(tmpbuf); - if(result.error() == SUCCESS) { - if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; } - advance_root_scalar("bool"); - } - return result; + // We have a boolean if we have either "true" or "false" and the next character is either + // a structural character or whitespace. We also check that the length is correct: + // "true" and "false" are 4 and 5 characters long, respectively. + bool value_true = (max_len >= 4 && !atomparsing::str4ncmp(json, "true") && + (max_len == 4 || jsoncharutils::is_structural_or_whitespace(json[4]))); + bool value_false = (max_len >= 5 && !atomparsing::str4ncmp(json, "false") && + (max_len == 5 || jsoncharutils::is_structural_or_whitespace(json[5]))); + if(value_true == false && value_false == false) { return incorrect_type_error("Not a boolean"); } + if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; } + advance_root_scalar("bool"); + return value_true; } + simdjson_inline simdjson_result value_iterator::is_root_null(bool check_trailing) noexcept { auto max_len = peek_root_length(); auto json = peek_root_scalar("null"); @@ -54591,7 +54764,8 @@ class value_iterator { * * @returns Whether the object had any fields (returns false for empty). * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent* - * array or object is incomplete). + * array or object is incomplete). An INCOMPLETE_ARRAY_OR_OBJECT is an unrecoverable error that + * invalidates the document. */ simdjson_warn_unused simdjson_inline simdjson_result started_object() noexcept; /** @@ -54601,7 +54775,8 @@ class value_iterator { * * @returns Whether the object had any fields (returns false for empty). * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent* - * array or object is incomplete). + * array or object is incomplete). An INCOMPLETE_ARRAY_OR_OBJECT is an unrecoverable error that + * invalidates the document. */ simdjson_warn_unused simdjson_inline simdjson_result started_root_object() noexcept; @@ -54723,7 +54898,8 @@ class value_iterator { * * @returns Whether the array had any elements (returns false for empty). * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent* - * array or object is incomplete). + * array or object is incomplete). An INCOMPLETE_ARRAY_OR_OBJECT is an unrecoverable error that + * invalidates the document. */ simdjson_warn_unused simdjson_inline simdjson_result started_array() noexcept; /** @@ -54733,7 +54909,8 @@ class value_iterator { * * @returns Whether the array had any elements (returns false for empty). * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent* - * array or object is incomplete). + * array or object is incomplete). An INCOMPLETE_ARRAY_OR_OBJECT is an unrecoverable error that + * invalidates the document. */ simdjson_warn_unused simdjson_inline simdjson_result started_root_array() noexcept; @@ -55031,22 +55208,28 @@ class value { noexcept #endif { -#if SIMDJSON_SUPPORTS_DESERIALIZATION - if constexpr (custom_deserializable) { + #if SIMDJSON_SUPPORTS_DESERIALIZATION + if constexpr (custom_deserializable) { return deserialize(*this, out); - } else { -#endif // SIMDJSON_SUPPORTS_DESERIALIZATION - // Unless the simdjson library or the user provides an inline implementation, calling this method should - // immediately fail. - static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. " - "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " - "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), " - " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template." - " You may also add support for custom types, see our documentation."); - static_cast(out); // to get rid of unused errors - return UNINITIALIZED; -#if SIMDJSON_SUPPORTS_DESERIALIZATION - } + } else { + static_assert(!sizeof(T), "The get method with type T is not implemented by the simdjson library. " + "And you do not seem to have added support for it. Indeed, we have that " + "simdjson::custom_deserializable is false and the type T is not a default type " + "such as ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " + "int64_t, double, or bool."); + static_cast(out); // to get rid of unused errors + return UNINITIALIZED; + } +#else // SIMDJSON_SUPPORTS_DESERIALIZATION + // Unless the simdjson library or the user provides an inline implementation, calling this method should + // immediately fail. + static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. " + "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " + "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), " + " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template." + " You may also add support for custom types, see our documentation."); + static_cast(out); // to get rid of unused errors + return UNINITIALIZED; #endif } @@ -57681,20 +57864,27 @@ class document { if constexpr (custom_deserializable) { return deserialize(*this, out); } else { -#endif // SIMDJSON_SUPPORTS_DESERIALIZATION - // Unless the simdjson library or the user provides an inline implementation, calling this method should - // immediately fail. - static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. " - "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " - "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), " - " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template." - " You may also add support for custom types, see our documentation."); + static_assert(!sizeof(T), "The get method with type T is not implemented by the simdjson library. " + "And you do not seem to have added support for it. Indeed, we have that " + "simdjson::custom_deserializable is false and the type T is not a default type " + "such as ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " + "int64_t, double, or bool."); static_cast(out); // to get rid of unused errors return UNINITIALIZED; -#if SIMDJSON_SUPPORTS_DESERIALIZATION } -#endif +#else // SIMDJSON_SUPPORTS_DESERIALIZATION + // Unless the simdjson library or the user provides an inline implementation, calling this method should + // immediately fail. + static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. " + "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " + "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), " + " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template." + " You may also add support for custom types, see our documentation."); + static_cast(out); // to get rid of unused errors + return UNINITIALIZED; +#endif // SIMDJSON_SUPPORTS_DESERIALIZATION } + /** @overload template error_code get(T &out) & noexcept */ template simdjson_deprecated simdjson_inline error_code get(T &out) && noexcept; @@ -58256,20 +58446,27 @@ class document_reference { if constexpr (custom_deserializable) { return deserialize(*this, out); } else { -#endif // SIMDJSON_SUPPORTS_DESERIALIZATION - // Unless the simdjson library or the user provides an inline implementation, calling this method should - // immediately fail. - static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. " - "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " - "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), " - " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template." - " You may also add support for custom types, see our documentation."); + static_assert(!sizeof(T), "The get method with type T is not implemented by the simdjson library. " + "And you do not seem to have added support for it. Indeed, we have that " + "simdjson::custom_deserializable is false and the type T is not a default type " + "such as ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " + "int64_t, double, or bool."); static_cast(out); // to get rid of unused errors return UNINITIALIZED; -#if SIMDJSON_SUPPORTS_DESERIALIZATION } -#endif +#else // SIMDJSON_SUPPORTS_DESERIALIZATION + // Unless the simdjson library or the user provides an inline implementation, calling this method should + // immediately fail. + static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. " + "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " + "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), " + " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template." + " You may also add support for custom types, see our documentation."); + static_cast(out); // to get rid of unused errors + return UNINITIALIZED; +#endif // SIMDJSON_SUPPORTS_DESERIALIZATION } + /** @overload template error_code get(T &out) & noexcept */ template simdjson_inline error_code get(T &out) && noexcept; simdjson_inline simdjson_result raw_json() noexcept; @@ -59444,6 +59641,16 @@ error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept { return SUCCESS; } +template + requires(!require_custom_serialization) +error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(std::is_nothrow_constructible_v) { + std::string_view str; + SIMDJSON_TRY(val.get_string().get(str)); + out = T{str}; + return SUCCESS; +} + + /** * STL containers have several constructors including one that takes a single * size argument. Thus, some compilers (Visual Studio) will not be able to @@ -59489,6 +59696,39 @@ error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) { } +/** + * We want to support std::map and std::unordered_map but only for + * string-keyed types. + */ + template + requires(!require_custom_serialization) +error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) { + using value_type = typename std::remove_cvref_t::mapped_type; + static_assert( + deserializable, + "The specified value type inside the container must itself be deserializable"); + static_assert( + std::is_default_constructible_v, + "The specified value type inside the container must default constructible."); + haswell::ondemand::object obj; + SIMDJSON_TRY(val.get_object().get(obj)); + for (auto field : obj) { + std::string_view key; + SIMDJSON_TRY(field.unescaped_key().get(key)); + value_type this_value; + SIMDJSON_TRY(field.value().get().get(this_value)); + [[maybe_unused]] std::pair result = out.emplace(key, this_value); + // unclear what to do if the key already exists + // if (result.second == false) { + // // key already exists + // } + } + (void)out; + return SUCCESS; +} + + + /** * This CPO (Customization Point Object) will help deserialize into @@ -64713,19 +64953,23 @@ simdjson_warn_unused simdjson_inline simdjson_result value_iterator::get } return result; } + simdjson_warn_unused simdjson_inline simdjson_result value_iterator::get_root_bool(bool check_trailing) noexcept { auto max_len = peek_root_length(); auto json = peek_root_scalar("bool"); - uint8_t tmpbuf[5+1+1]; // +1 for null termination - tmpbuf[5+1] = '\0'; // make sure that buffer is always null terminated. - if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 5+1)) { return incorrect_type_error("Not a boolean"); } - auto result = parse_bool(tmpbuf); - if(result.error() == SUCCESS) { - if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; } - advance_root_scalar("bool"); - } - return result; + // We have a boolean if we have either "true" or "false" and the next character is either + // a structural character or whitespace. We also check that the length is correct: + // "true" and "false" are 4 and 5 characters long, respectively. + bool value_true = (max_len >= 4 && !atomparsing::str4ncmp(json, "true") && + (max_len == 4 || jsoncharutils::is_structural_or_whitespace(json[4]))); + bool value_false = (max_len >= 5 && !atomparsing::str4ncmp(json, "false") && + (max_len == 5 || jsoncharutils::is_structural_or_whitespace(json[5]))); + if(value_true == false && value_false == false) { return incorrect_type_error("Not a boolean"); } + if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; } + advance_root_scalar("bool"); + return value_true; } + simdjson_inline simdjson_result value_iterator::is_root_null(bool check_trailing) noexcept { auto max_len = peek_root_length(); auto json = peek_root_scalar("null"); @@ -66056,7 +66300,8 @@ class value_iterator { * * @returns Whether the object had any fields (returns false for empty). * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent* - * array or object is incomplete). + * array or object is incomplete). An INCOMPLETE_ARRAY_OR_OBJECT is an unrecoverable error that + * invalidates the document. */ simdjson_warn_unused simdjson_inline simdjson_result started_object() noexcept; /** @@ -66066,7 +66311,8 @@ class value_iterator { * * @returns Whether the object had any fields (returns false for empty). * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent* - * array or object is incomplete). + * array or object is incomplete). An INCOMPLETE_ARRAY_OR_OBJECT is an unrecoverable error that + * invalidates the document. */ simdjson_warn_unused simdjson_inline simdjson_result started_root_object() noexcept; @@ -66188,7 +66434,8 @@ class value_iterator { * * @returns Whether the array had any elements (returns false for empty). * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent* - * array or object is incomplete). + * array or object is incomplete). An INCOMPLETE_ARRAY_OR_OBJECT is an unrecoverable error that + * invalidates the document. */ simdjson_warn_unused simdjson_inline simdjson_result started_array() noexcept; /** @@ -66198,7 +66445,8 @@ class value_iterator { * * @returns Whether the array had any elements (returns false for empty). * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent* - * array or object is incomplete). + * array or object is incomplete). An INCOMPLETE_ARRAY_OR_OBJECT is an unrecoverable error that + * invalidates the document. */ simdjson_warn_unused simdjson_inline simdjson_result started_root_array() noexcept; @@ -66496,22 +66744,28 @@ class value { noexcept #endif { -#if SIMDJSON_SUPPORTS_DESERIALIZATION - if constexpr (custom_deserializable) { + #if SIMDJSON_SUPPORTS_DESERIALIZATION + if constexpr (custom_deserializable) { return deserialize(*this, out); - } else { -#endif // SIMDJSON_SUPPORTS_DESERIALIZATION - // Unless the simdjson library or the user provides an inline implementation, calling this method should - // immediately fail. - static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. " - "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " - "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), " - " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template." - " You may also add support for custom types, see our documentation."); - static_cast(out); // to get rid of unused errors - return UNINITIALIZED; -#if SIMDJSON_SUPPORTS_DESERIALIZATION - } + } else { + static_assert(!sizeof(T), "The get method with type T is not implemented by the simdjson library. " + "And you do not seem to have added support for it. Indeed, we have that " + "simdjson::custom_deserializable is false and the type T is not a default type " + "such as ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " + "int64_t, double, or bool."); + static_cast(out); // to get rid of unused errors + return UNINITIALIZED; + } +#else // SIMDJSON_SUPPORTS_DESERIALIZATION + // Unless the simdjson library or the user provides an inline implementation, calling this method should + // immediately fail. + static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. " + "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " + "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), " + " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template." + " You may also add support for custom types, see our documentation."); + static_cast(out); // to get rid of unused errors + return UNINITIALIZED; #endif } @@ -69146,20 +69400,27 @@ class document { if constexpr (custom_deserializable) { return deserialize(*this, out); } else { -#endif // SIMDJSON_SUPPORTS_DESERIALIZATION - // Unless the simdjson library or the user provides an inline implementation, calling this method should - // immediately fail. - static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. " - "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " - "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), " - " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template." - " You may also add support for custom types, see our documentation."); + static_assert(!sizeof(T), "The get method with type T is not implemented by the simdjson library. " + "And you do not seem to have added support for it. Indeed, we have that " + "simdjson::custom_deserializable is false and the type T is not a default type " + "such as ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " + "int64_t, double, or bool."); static_cast(out); // to get rid of unused errors return UNINITIALIZED; -#if SIMDJSON_SUPPORTS_DESERIALIZATION } -#endif +#else // SIMDJSON_SUPPORTS_DESERIALIZATION + // Unless the simdjson library or the user provides an inline implementation, calling this method should + // immediately fail. + static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. " + "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " + "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), " + " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template." + " You may also add support for custom types, see our documentation."); + static_cast(out); // to get rid of unused errors + return UNINITIALIZED; +#endif // SIMDJSON_SUPPORTS_DESERIALIZATION } + /** @overload template error_code get(T &out) & noexcept */ template simdjson_deprecated simdjson_inline error_code get(T &out) && noexcept; @@ -69721,20 +69982,27 @@ class document_reference { if constexpr (custom_deserializable) { return deserialize(*this, out); } else { -#endif // SIMDJSON_SUPPORTS_DESERIALIZATION - // Unless the simdjson library or the user provides an inline implementation, calling this method should - // immediately fail. - static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. " - "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " - "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), " - " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template." - " You may also add support for custom types, see our documentation."); + static_assert(!sizeof(T), "The get method with type T is not implemented by the simdjson library. " + "And you do not seem to have added support for it. Indeed, we have that " + "simdjson::custom_deserializable is false and the type T is not a default type " + "such as ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " + "int64_t, double, or bool."); static_cast(out); // to get rid of unused errors return UNINITIALIZED; -#if SIMDJSON_SUPPORTS_DESERIALIZATION } -#endif +#else // SIMDJSON_SUPPORTS_DESERIALIZATION + // Unless the simdjson library or the user provides an inline implementation, calling this method should + // immediately fail. + static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. " + "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " + "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), " + " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template." + " You may also add support for custom types, see our documentation."); + static_cast(out); // to get rid of unused errors + return UNINITIALIZED; +#endif // SIMDJSON_SUPPORTS_DESERIALIZATION } + /** @overload template error_code get(T &out) & noexcept */ template simdjson_inline error_code get(T &out) && noexcept; simdjson_inline simdjson_result raw_json() noexcept; @@ -70909,6 +71177,16 @@ error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept { return SUCCESS; } +template + requires(!require_custom_serialization) +error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(std::is_nothrow_constructible_v) { + std::string_view str; + SIMDJSON_TRY(val.get_string().get(str)); + out = T{str}; + return SUCCESS; +} + + /** * STL containers have several constructors including one that takes a single * size argument. Thus, some compilers (Visual Studio) will not be able to @@ -70954,6 +71232,39 @@ error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) { } +/** + * We want to support std::map and std::unordered_map but only for + * string-keyed types. + */ + template + requires(!require_custom_serialization) +error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) { + using value_type = typename std::remove_cvref_t::mapped_type; + static_assert( + deserializable, + "The specified value type inside the container must itself be deserializable"); + static_assert( + std::is_default_constructible_v, + "The specified value type inside the container must default constructible."); + icelake::ondemand::object obj; + SIMDJSON_TRY(val.get_object().get(obj)); + for (auto field : obj) { + std::string_view key; + SIMDJSON_TRY(field.unescaped_key().get(key)); + value_type this_value; + SIMDJSON_TRY(field.value().get().get(this_value)); + [[maybe_unused]] std::pair result = out.emplace(key, this_value); + // unclear what to do if the key already exists + // if (result.second == false) { + // // key already exists + // } + } + (void)out; + return SUCCESS; +} + + + /** * This CPO (Customization Point Object) will help deserialize into @@ -76178,19 +76489,23 @@ simdjson_warn_unused simdjson_inline simdjson_result value_iterator::get } return result; } + simdjson_warn_unused simdjson_inline simdjson_result value_iterator::get_root_bool(bool check_trailing) noexcept { auto max_len = peek_root_length(); auto json = peek_root_scalar("bool"); - uint8_t tmpbuf[5+1+1]; // +1 for null termination - tmpbuf[5+1] = '\0'; // make sure that buffer is always null terminated. - if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 5+1)) { return incorrect_type_error("Not a boolean"); } - auto result = parse_bool(tmpbuf); - if(result.error() == SUCCESS) { - if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; } - advance_root_scalar("bool"); - } - return result; + // We have a boolean if we have either "true" or "false" and the next character is either + // a structural character or whitespace. We also check that the length is correct: + // "true" and "false" are 4 and 5 characters long, respectively. + bool value_true = (max_len >= 4 && !atomparsing::str4ncmp(json, "true") && + (max_len == 4 || jsoncharutils::is_structural_or_whitespace(json[4]))); + bool value_false = (max_len >= 5 && !atomparsing::str4ncmp(json, "false") && + (max_len == 5 || jsoncharutils::is_structural_or_whitespace(json[5]))); + if(value_true == false && value_false == false) { return incorrect_type_error("Not a boolean"); } + if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; } + advance_root_scalar("bool"); + return value_true; } + simdjson_inline simdjson_result value_iterator::is_root_null(bool check_trailing) noexcept { auto max_len = peek_root_length(); auto json = peek_root_scalar("null"); @@ -77638,7 +77953,8 @@ class value_iterator { * * @returns Whether the object had any fields (returns false for empty). * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent* - * array or object is incomplete). + * array or object is incomplete). An INCOMPLETE_ARRAY_OR_OBJECT is an unrecoverable error that + * invalidates the document. */ simdjson_warn_unused simdjson_inline simdjson_result started_object() noexcept; /** @@ -77648,7 +77964,8 @@ class value_iterator { * * @returns Whether the object had any fields (returns false for empty). * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent* - * array or object is incomplete). + * array or object is incomplete). An INCOMPLETE_ARRAY_OR_OBJECT is an unrecoverable error that + * invalidates the document. */ simdjson_warn_unused simdjson_inline simdjson_result started_root_object() noexcept; @@ -77770,7 +78087,8 @@ class value_iterator { * * @returns Whether the array had any elements (returns false for empty). * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent* - * array or object is incomplete). + * array or object is incomplete). An INCOMPLETE_ARRAY_OR_OBJECT is an unrecoverable error that + * invalidates the document. */ simdjson_warn_unused simdjson_inline simdjson_result started_array() noexcept; /** @@ -77780,7 +78098,8 @@ class value_iterator { * * @returns Whether the array had any elements (returns false for empty). * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent* - * array or object is incomplete). + * array or object is incomplete). An INCOMPLETE_ARRAY_OR_OBJECT is an unrecoverable error that + * invalidates the document. */ simdjson_warn_unused simdjson_inline simdjson_result started_root_array() noexcept; @@ -78078,22 +78397,28 @@ class value { noexcept #endif { -#if SIMDJSON_SUPPORTS_DESERIALIZATION - if constexpr (custom_deserializable) { + #if SIMDJSON_SUPPORTS_DESERIALIZATION + if constexpr (custom_deserializable) { return deserialize(*this, out); - } else { -#endif // SIMDJSON_SUPPORTS_DESERIALIZATION - // Unless the simdjson library or the user provides an inline implementation, calling this method should - // immediately fail. - static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. " - "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " - "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), " - " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template." - " You may also add support for custom types, see our documentation."); - static_cast(out); // to get rid of unused errors - return UNINITIALIZED; -#if SIMDJSON_SUPPORTS_DESERIALIZATION - } + } else { + static_assert(!sizeof(T), "The get method with type T is not implemented by the simdjson library. " + "And you do not seem to have added support for it. Indeed, we have that " + "simdjson::custom_deserializable is false and the type T is not a default type " + "such as ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " + "int64_t, double, or bool."); + static_cast(out); // to get rid of unused errors + return UNINITIALIZED; + } +#else // SIMDJSON_SUPPORTS_DESERIALIZATION + // Unless the simdjson library or the user provides an inline implementation, calling this method should + // immediately fail. + static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. " + "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " + "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), " + " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template." + " You may also add support for custom types, see our documentation."); + static_cast(out); // to get rid of unused errors + return UNINITIALIZED; #endif } @@ -80728,20 +81053,27 @@ class document { if constexpr (custom_deserializable) { return deserialize(*this, out); } else { -#endif // SIMDJSON_SUPPORTS_DESERIALIZATION - // Unless the simdjson library or the user provides an inline implementation, calling this method should - // immediately fail. - static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. " - "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " - "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), " - " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template." - " You may also add support for custom types, see our documentation."); + static_assert(!sizeof(T), "The get method with type T is not implemented by the simdjson library. " + "And you do not seem to have added support for it. Indeed, we have that " + "simdjson::custom_deserializable is false and the type T is not a default type " + "such as ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " + "int64_t, double, or bool."); static_cast(out); // to get rid of unused errors return UNINITIALIZED; -#if SIMDJSON_SUPPORTS_DESERIALIZATION } -#endif +#else // SIMDJSON_SUPPORTS_DESERIALIZATION + // Unless the simdjson library or the user provides an inline implementation, calling this method should + // immediately fail. + static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. " + "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " + "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), " + " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template." + " You may also add support for custom types, see our documentation."); + static_cast(out); // to get rid of unused errors + return UNINITIALIZED; +#endif // SIMDJSON_SUPPORTS_DESERIALIZATION } + /** @overload template error_code get(T &out) & noexcept */ template simdjson_deprecated simdjson_inline error_code get(T &out) && noexcept; @@ -81303,20 +81635,27 @@ class document_reference { if constexpr (custom_deserializable) { return deserialize(*this, out); } else { -#endif // SIMDJSON_SUPPORTS_DESERIALIZATION - // Unless the simdjson library or the user provides an inline implementation, calling this method should - // immediately fail. - static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. " - "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " - "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), " - " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template." - " You may also add support for custom types, see our documentation."); + static_assert(!sizeof(T), "The get method with type T is not implemented by the simdjson library. " + "And you do not seem to have added support for it. Indeed, we have that " + "simdjson::custom_deserializable is false and the type T is not a default type " + "such as ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " + "int64_t, double, or bool."); static_cast(out); // to get rid of unused errors return UNINITIALIZED; -#if SIMDJSON_SUPPORTS_DESERIALIZATION } -#endif +#else // SIMDJSON_SUPPORTS_DESERIALIZATION + // Unless the simdjson library or the user provides an inline implementation, calling this method should + // immediately fail. + static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. " + "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " + "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), " + " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template." + " You may also add support for custom types, see our documentation."); + static_cast(out); // to get rid of unused errors + return UNINITIALIZED; +#endif // SIMDJSON_SUPPORTS_DESERIALIZATION } + /** @overload template error_code get(T &out) & noexcept */ template simdjson_inline error_code get(T &out) && noexcept; simdjson_inline simdjson_result raw_json() noexcept; @@ -82491,6 +82830,16 @@ error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept { return SUCCESS; } +template + requires(!require_custom_serialization) +error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(std::is_nothrow_constructible_v) { + std::string_view str; + SIMDJSON_TRY(val.get_string().get(str)); + out = T{str}; + return SUCCESS; +} + + /** * STL containers have several constructors including one that takes a single * size argument. Thus, some compilers (Visual Studio) will not be able to @@ -82536,6 +82885,39 @@ error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) { } +/** + * We want to support std::map and std::unordered_map but only for + * string-keyed types. + */ + template + requires(!require_custom_serialization) +error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) { + using value_type = typename std::remove_cvref_t::mapped_type; + static_assert( + deserializable, + "The specified value type inside the container must itself be deserializable"); + static_assert( + std::is_default_constructible_v, + "The specified value type inside the container must default constructible."); + ppc64::ondemand::object obj; + SIMDJSON_TRY(val.get_object().get(obj)); + for (auto field : obj) { + std::string_view key; + SIMDJSON_TRY(field.unescaped_key().get(key)); + value_type this_value; + SIMDJSON_TRY(field.value().get().get(this_value)); + [[maybe_unused]] std::pair result = out.emplace(key, this_value); + // unclear what to do if the key already exists + // if (result.second == false) { + // // key already exists + // } + } + (void)out; + return SUCCESS; +} + + + /** * This CPO (Customization Point Object) will help deserialize into @@ -87760,19 +88142,23 @@ simdjson_warn_unused simdjson_inline simdjson_result value_iterator::get } return result; } + simdjson_warn_unused simdjson_inline simdjson_result value_iterator::get_root_bool(bool check_trailing) noexcept { auto max_len = peek_root_length(); auto json = peek_root_scalar("bool"); - uint8_t tmpbuf[5+1+1]; // +1 for null termination - tmpbuf[5+1] = '\0'; // make sure that buffer is always null terminated. - if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 5+1)) { return incorrect_type_error("Not a boolean"); } - auto result = parse_bool(tmpbuf); - if(result.error() == SUCCESS) { - if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; } - advance_root_scalar("bool"); - } - return result; + // We have a boolean if we have either "true" or "false" and the next character is either + // a structural character or whitespace. We also check that the length is correct: + // "true" and "false" are 4 and 5 characters long, respectively. + bool value_true = (max_len >= 4 && !atomparsing::str4ncmp(json, "true") && + (max_len == 4 || jsoncharutils::is_structural_or_whitespace(json[4]))); + bool value_false = (max_len >= 5 && !atomparsing::str4ncmp(json, "false") && + (max_len == 5 || jsoncharutils::is_structural_or_whitespace(json[5]))); + if(value_true == false && value_false == false) { return incorrect_type_error("Not a boolean"); } + if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; } + advance_root_scalar("bool"); + return value_true; } + simdjson_inline simdjson_result value_iterator::is_root_null(bool check_trailing) noexcept { auto max_len = peek_root_length(); auto json = peek_root_scalar("null"); @@ -89537,7 +89923,8 @@ class value_iterator { * * @returns Whether the object had any fields (returns false for empty). * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent* - * array or object is incomplete). + * array or object is incomplete). An INCOMPLETE_ARRAY_OR_OBJECT is an unrecoverable error that + * invalidates the document. */ simdjson_warn_unused simdjson_inline simdjson_result started_object() noexcept; /** @@ -89547,7 +89934,8 @@ class value_iterator { * * @returns Whether the object had any fields (returns false for empty). * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent* - * array or object is incomplete). + * array or object is incomplete). An INCOMPLETE_ARRAY_OR_OBJECT is an unrecoverable error that + * invalidates the document. */ simdjson_warn_unused simdjson_inline simdjson_result started_root_object() noexcept; @@ -89669,7 +90057,8 @@ class value_iterator { * * @returns Whether the array had any elements (returns false for empty). * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent* - * array or object is incomplete). + * array or object is incomplete). An INCOMPLETE_ARRAY_OR_OBJECT is an unrecoverable error that + * invalidates the document. */ simdjson_warn_unused simdjson_inline simdjson_result started_array() noexcept; /** @@ -89679,7 +90068,8 @@ class value_iterator { * * @returns Whether the array had any elements (returns false for empty). * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent* - * array or object is incomplete). + * array or object is incomplete). An INCOMPLETE_ARRAY_OR_OBJECT is an unrecoverable error that + * invalidates the document. */ simdjson_warn_unused simdjson_inline simdjson_result started_root_array() noexcept; @@ -89977,22 +90367,28 @@ class value { noexcept #endif { -#if SIMDJSON_SUPPORTS_DESERIALIZATION - if constexpr (custom_deserializable) { + #if SIMDJSON_SUPPORTS_DESERIALIZATION + if constexpr (custom_deserializable) { return deserialize(*this, out); - } else { -#endif // SIMDJSON_SUPPORTS_DESERIALIZATION - // Unless the simdjson library or the user provides an inline implementation, calling this method should - // immediately fail. - static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. " - "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " - "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), " - " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template." - " You may also add support for custom types, see our documentation."); - static_cast(out); // to get rid of unused errors - return UNINITIALIZED; -#if SIMDJSON_SUPPORTS_DESERIALIZATION - } + } else { + static_assert(!sizeof(T), "The get method with type T is not implemented by the simdjson library. " + "And you do not seem to have added support for it. Indeed, we have that " + "simdjson::custom_deserializable is false and the type T is not a default type " + "such as ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " + "int64_t, double, or bool."); + static_cast(out); // to get rid of unused errors + return UNINITIALIZED; + } +#else // SIMDJSON_SUPPORTS_DESERIALIZATION + // Unless the simdjson library or the user provides an inline implementation, calling this method should + // immediately fail. + static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. " + "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " + "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), " + " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template." + " You may also add support for custom types, see our documentation."); + static_cast(out); // to get rid of unused errors + return UNINITIALIZED; #endif } @@ -92627,20 +93023,27 @@ class document { if constexpr (custom_deserializable) { return deserialize(*this, out); } else { -#endif // SIMDJSON_SUPPORTS_DESERIALIZATION - // Unless the simdjson library or the user provides an inline implementation, calling this method should - // immediately fail. - static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. " - "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " - "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), " - " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template." - " You may also add support for custom types, see our documentation."); + static_assert(!sizeof(T), "The get method with type T is not implemented by the simdjson library. " + "And you do not seem to have added support for it. Indeed, we have that " + "simdjson::custom_deserializable is false and the type T is not a default type " + "such as ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " + "int64_t, double, or bool."); static_cast(out); // to get rid of unused errors return UNINITIALIZED; -#if SIMDJSON_SUPPORTS_DESERIALIZATION } -#endif +#else // SIMDJSON_SUPPORTS_DESERIALIZATION + // Unless the simdjson library or the user provides an inline implementation, calling this method should + // immediately fail. + static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. " + "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " + "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), " + " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template." + " You may also add support for custom types, see our documentation."); + static_cast(out); // to get rid of unused errors + return UNINITIALIZED; +#endif // SIMDJSON_SUPPORTS_DESERIALIZATION } + /** @overload template error_code get(T &out) & noexcept */ template simdjson_deprecated simdjson_inline error_code get(T &out) && noexcept; @@ -93202,20 +93605,27 @@ class document_reference { if constexpr (custom_deserializable) { return deserialize(*this, out); } else { -#endif // SIMDJSON_SUPPORTS_DESERIALIZATION - // Unless the simdjson library or the user provides an inline implementation, calling this method should - // immediately fail. - static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. " - "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " - "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), " - " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template." - " You may also add support for custom types, see our documentation."); + static_assert(!sizeof(T), "The get method with type T is not implemented by the simdjson library. " + "And you do not seem to have added support for it. Indeed, we have that " + "simdjson::custom_deserializable is false and the type T is not a default type " + "such as ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " + "int64_t, double, or bool."); static_cast(out); // to get rid of unused errors return UNINITIALIZED; -#if SIMDJSON_SUPPORTS_DESERIALIZATION } -#endif +#else // SIMDJSON_SUPPORTS_DESERIALIZATION + // Unless the simdjson library or the user provides an inline implementation, calling this method should + // immediately fail. + static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. " + "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " + "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), " + " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template." + " You may also add support for custom types, see our documentation."); + static_cast(out); // to get rid of unused errors + return UNINITIALIZED; +#endif // SIMDJSON_SUPPORTS_DESERIALIZATION } + /** @overload template error_code get(T &out) & noexcept */ template simdjson_inline error_code get(T &out) && noexcept; simdjson_inline simdjson_result raw_json() noexcept; @@ -94390,6 +94800,16 @@ error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept { return SUCCESS; } +template + requires(!require_custom_serialization) +error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(std::is_nothrow_constructible_v) { + std::string_view str; + SIMDJSON_TRY(val.get_string().get(str)); + out = T{str}; + return SUCCESS; +} + + /** * STL containers have several constructors including one that takes a single * size argument. Thus, some compilers (Visual Studio) will not be able to @@ -94435,6 +94855,39 @@ error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) { } +/** + * We want to support std::map and std::unordered_map but only for + * string-keyed types. + */ + template + requires(!require_custom_serialization) +error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) { + using value_type = typename std::remove_cvref_t::mapped_type; + static_assert( + deserializable, + "The specified value type inside the container must itself be deserializable"); + static_assert( + std::is_default_constructible_v, + "The specified value type inside the container must default constructible."); + westmere::ondemand::object obj; + SIMDJSON_TRY(val.get_object().get(obj)); + for (auto field : obj) { + std::string_view key; + SIMDJSON_TRY(field.unescaped_key().get(key)); + value_type this_value; + SIMDJSON_TRY(field.value().get().get(this_value)); + [[maybe_unused]] std::pair result = out.emplace(key, this_value); + // unclear what to do if the key already exists + // if (result.second == false) { + // // key already exists + // } + } + (void)out; + return SUCCESS; +} + + + /** * This CPO (Customization Point Object) will help deserialize into @@ -99659,19 +100112,23 @@ simdjson_warn_unused simdjson_inline simdjson_result value_iterator::get } return result; } + simdjson_warn_unused simdjson_inline simdjson_result value_iterator::get_root_bool(bool check_trailing) noexcept { auto max_len = peek_root_length(); auto json = peek_root_scalar("bool"); - uint8_t tmpbuf[5+1+1]; // +1 for null termination - tmpbuf[5+1] = '\0'; // make sure that buffer is always null terminated. - if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 5+1)) { return incorrect_type_error("Not a boolean"); } - auto result = parse_bool(tmpbuf); - if(result.error() == SUCCESS) { - if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; } - advance_root_scalar("bool"); - } - return result; + // We have a boolean if we have either "true" or "false" and the next character is either + // a structural character or whitespace. We also check that the length is correct: + // "true" and "false" are 4 and 5 characters long, respectively. + bool value_true = (max_len >= 4 && !atomparsing::str4ncmp(json, "true") && + (max_len == 4 || jsoncharutils::is_structural_or_whitespace(json[4]))); + bool value_false = (max_len >= 5 && !atomparsing::str4ncmp(json, "false") && + (max_len == 5 || jsoncharutils::is_structural_or_whitespace(json[5]))); + if(value_true == false && value_false == false) { return incorrect_type_error("Not a boolean"); } + if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; } + advance_root_scalar("bool"); + return value_true; } + simdjson_inline simdjson_result value_iterator::is_root_null(bool check_trailing) noexcept { auto max_len = peek_root_length(); auto json = peek_root_scalar("null"); @@ -100913,7 +101370,8 @@ class value_iterator { * * @returns Whether the object had any fields (returns false for empty). * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent* - * array or object is incomplete). + * array or object is incomplete). An INCOMPLETE_ARRAY_OR_OBJECT is an unrecoverable error that + * invalidates the document. */ simdjson_warn_unused simdjson_inline simdjson_result started_object() noexcept; /** @@ -100923,7 +101381,8 @@ class value_iterator { * * @returns Whether the object had any fields (returns false for empty). * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent* - * array or object is incomplete). + * array or object is incomplete). An INCOMPLETE_ARRAY_OR_OBJECT is an unrecoverable error that + * invalidates the document. */ simdjson_warn_unused simdjson_inline simdjson_result started_root_object() noexcept; @@ -101045,7 +101504,8 @@ class value_iterator { * * @returns Whether the array had any elements (returns false for empty). * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent* - * array or object is incomplete). + * array or object is incomplete). An INCOMPLETE_ARRAY_OR_OBJECT is an unrecoverable error that + * invalidates the document. */ simdjson_warn_unused simdjson_inline simdjson_result started_array() noexcept; /** @@ -101055,7 +101515,8 @@ class value_iterator { * * @returns Whether the array had any elements (returns false for empty). * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent* - * array or object is incomplete). + * array or object is incomplete). An INCOMPLETE_ARRAY_OR_OBJECT is an unrecoverable error that + * invalidates the document. */ simdjson_warn_unused simdjson_inline simdjson_result started_root_array() noexcept; @@ -101353,22 +101814,28 @@ class value { noexcept #endif { -#if SIMDJSON_SUPPORTS_DESERIALIZATION - if constexpr (custom_deserializable) { + #if SIMDJSON_SUPPORTS_DESERIALIZATION + if constexpr (custom_deserializable) { return deserialize(*this, out); - } else { -#endif // SIMDJSON_SUPPORTS_DESERIALIZATION - // Unless the simdjson library or the user provides an inline implementation, calling this method should - // immediately fail. - static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. " - "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " - "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), " - " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template." - " You may also add support for custom types, see our documentation."); - static_cast(out); // to get rid of unused errors - return UNINITIALIZED; -#if SIMDJSON_SUPPORTS_DESERIALIZATION - } + } else { + static_assert(!sizeof(T), "The get method with type T is not implemented by the simdjson library. " + "And you do not seem to have added support for it. Indeed, we have that " + "simdjson::custom_deserializable is false and the type T is not a default type " + "such as ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " + "int64_t, double, or bool."); + static_cast(out); // to get rid of unused errors + return UNINITIALIZED; + } +#else // SIMDJSON_SUPPORTS_DESERIALIZATION + // Unless the simdjson library or the user provides an inline implementation, calling this method should + // immediately fail. + static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. " + "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " + "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), " + " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template." + " You may also add support for custom types, see our documentation."); + static_cast(out); // to get rid of unused errors + return UNINITIALIZED; #endif } @@ -104003,20 +104470,27 @@ class document { if constexpr (custom_deserializable) { return deserialize(*this, out); } else { -#endif // SIMDJSON_SUPPORTS_DESERIALIZATION - // Unless the simdjson library or the user provides an inline implementation, calling this method should - // immediately fail. - static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. " - "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " - "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), " - " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template." - " You may also add support for custom types, see our documentation."); + static_assert(!sizeof(T), "The get method with type T is not implemented by the simdjson library. " + "And you do not seem to have added support for it. Indeed, we have that " + "simdjson::custom_deserializable is false and the type T is not a default type " + "such as ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " + "int64_t, double, or bool."); static_cast(out); // to get rid of unused errors return UNINITIALIZED; -#if SIMDJSON_SUPPORTS_DESERIALIZATION } -#endif +#else // SIMDJSON_SUPPORTS_DESERIALIZATION + // Unless the simdjson library or the user provides an inline implementation, calling this method should + // immediately fail. + static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. " + "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " + "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), " + " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template." + " You may also add support for custom types, see our documentation."); + static_cast(out); // to get rid of unused errors + return UNINITIALIZED; +#endif // SIMDJSON_SUPPORTS_DESERIALIZATION } + /** @overload template error_code get(T &out) & noexcept */ template simdjson_deprecated simdjson_inline error_code get(T &out) && noexcept; @@ -104578,20 +105052,27 @@ class document_reference { if constexpr (custom_deserializable) { return deserialize(*this, out); } else { -#endif // SIMDJSON_SUPPORTS_DESERIALIZATION - // Unless the simdjson library or the user provides an inline implementation, calling this method should - // immediately fail. - static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. " - "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " - "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), " - " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template." - " You may also add support for custom types, see our documentation."); + static_assert(!sizeof(T), "The get method with type T is not implemented by the simdjson library. " + "And you do not seem to have added support for it. Indeed, we have that " + "simdjson::custom_deserializable is false and the type T is not a default type " + "such as ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " + "int64_t, double, or bool."); static_cast(out); // to get rid of unused errors return UNINITIALIZED; -#if SIMDJSON_SUPPORTS_DESERIALIZATION } -#endif +#else // SIMDJSON_SUPPORTS_DESERIALIZATION + // Unless the simdjson library or the user provides an inline implementation, calling this method should + // immediately fail. + static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. " + "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " + "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), " + " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template." + " You may also add support for custom types, see our documentation."); + static_cast(out); // to get rid of unused errors + return UNINITIALIZED; +#endif // SIMDJSON_SUPPORTS_DESERIALIZATION } + /** @overload template error_code get(T &out) & noexcept */ template simdjson_inline error_code get(T &out) && noexcept; simdjson_inline simdjson_result raw_json() noexcept; @@ -105766,6 +106247,16 @@ error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept { return SUCCESS; } +template + requires(!require_custom_serialization) +error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(std::is_nothrow_constructible_v) { + std::string_view str; + SIMDJSON_TRY(val.get_string().get(str)); + out = T{str}; + return SUCCESS; +} + + /** * STL containers have several constructors including one that takes a single * size argument. Thus, some compilers (Visual Studio) will not be able to @@ -105811,6 +106302,39 @@ error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) { } +/** + * We want to support std::map and std::unordered_map but only for + * string-keyed types. + */ + template + requires(!require_custom_serialization) +error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) { + using value_type = typename std::remove_cvref_t::mapped_type; + static_assert( + deserializable, + "The specified value type inside the container must itself be deserializable"); + static_assert( + std::is_default_constructible_v, + "The specified value type inside the container must default constructible."); + lsx::ondemand::object obj; + SIMDJSON_TRY(val.get_object().get(obj)); + for (auto field : obj) { + std::string_view key; + SIMDJSON_TRY(field.unescaped_key().get(key)); + value_type this_value; + SIMDJSON_TRY(field.value().get().get(this_value)); + [[maybe_unused]] std::pair result = out.emplace(key, this_value); + // unclear what to do if the key already exists + // if (result.second == false) { + // // key already exists + // } + } + (void)out; + return SUCCESS; +} + + + /** * This CPO (Customization Point Object) will help deserialize into @@ -111035,19 +111559,23 @@ simdjson_warn_unused simdjson_inline simdjson_result value_iterator::get } return result; } + simdjson_warn_unused simdjson_inline simdjson_result value_iterator::get_root_bool(bool check_trailing) noexcept { auto max_len = peek_root_length(); auto json = peek_root_scalar("bool"); - uint8_t tmpbuf[5+1+1]; // +1 for null termination - tmpbuf[5+1] = '\0'; // make sure that buffer is always null terminated. - if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 5+1)) { return incorrect_type_error("Not a boolean"); } - auto result = parse_bool(tmpbuf); - if(result.error() == SUCCESS) { - if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; } - advance_root_scalar("bool"); - } - return result; + // We have a boolean if we have either "true" or "false" and the next character is either + // a structural character or whitespace. We also check that the length is correct: + // "true" and "false" are 4 and 5 characters long, respectively. + bool value_true = (max_len >= 4 && !atomparsing::str4ncmp(json, "true") && + (max_len == 4 || jsoncharutils::is_structural_or_whitespace(json[4]))); + bool value_false = (max_len >= 5 && !atomparsing::str4ncmp(json, "false") && + (max_len == 5 || jsoncharutils::is_structural_or_whitespace(json[5]))); + if(value_true == false && value_false == false) { return incorrect_type_error("Not a boolean"); } + if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; } + advance_root_scalar("bool"); + return value_true; } + simdjson_inline simdjson_result value_iterator::is_root_null(bool check_trailing) noexcept { auto max_len = peek_root_length(); auto json = peek_root_scalar("null"); @@ -112302,7 +112830,8 @@ class value_iterator { * * @returns Whether the object had any fields (returns false for empty). * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent* - * array or object is incomplete). + * array or object is incomplete). An INCOMPLETE_ARRAY_OR_OBJECT is an unrecoverable error that + * invalidates the document. */ simdjson_warn_unused simdjson_inline simdjson_result started_object() noexcept; /** @@ -112312,7 +112841,8 @@ class value_iterator { * * @returns Whether the object had any fields (returns false for empty). * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent* - * array or object is incomplete). + * array or object is incomplete). An INCOMPLETE_ARRAY_OR_OBJECT is an unrecoverable error that + * invalidates the document. */ simdjson_warn_unused simdjson_inline simdjson_result started_root_object() noexcept; @@ -112434,7 +112964,8 @@ class value_iterator { * * @returns Whether the array had any elements (returns false for empty). * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent* - * array or object is incomplete). + * array or object is incomplete). An INCOMPLETE_ARRAY_OR_OBJECT is an unrecoverable error that + * invalidates the document. */ simdjson_warn_unused simdjson_inline simdjson_result started_array() noexcept; /** @@ -112444,7 +112975,8 @@ class value_iterator { * * @returns Whether the array had any elements (returns false for empty). * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent* - * array or object is incomplete). + * array or object is incomplete). An INCOMPLETE_ARRAY_OR_OBJECT is an unrecoverable error that + * invalidates the document. */ simdjson_warn_unused simdjson_inline simdjson_result started_root_array() noexcept; @@ -112742,22 +113274,28 @@ class value { noexcept #endif { -#if SIMDJSON_SUPPORTS_DESERIALIZATION - if constexpr (custom_deserializable) { + #if SIMDJSON_SUPPORTS_DESERIALIZATION + if constexpr (custom_deserializable) { return deserialize(*this, out); - } else { -#endif // SIMDJSON_SUPPORTS_DESERIALIZATION - // Unless the simdjson library or the user provides an inline implementation, calling this method should - // immediately fail. - static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. " - "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " - "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), " - " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template." - " You may also add support for custom types, see our documentation."); - static_cast(out); // to get rid of unused errors - return UNINITIALIZED; -#if SIMDJSON_SUPPORTS_DESERIALIZATION - } + } else { + static_assert(!sizeof(T), "The get method with type T is not implemented by the simdjson library. " + "And you do not seem to have added support for it. Indeed, we have that " + "simdjson::custom_deserializable is false and the type T is not a default type " + "such as ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " + "int64_t, double, or bool."); + static_cast(out); // to get rid of unused errors + return UNINITIALIZED; + } +#else // SIMDJSON_SUPPORTS_DESERIALIZATION + // Unless the simdjson library or the user provides an inline implementation, calling this method should + // immediately fail. + static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. " + "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " + "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), " + " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template." + " You may also add support for custom types, see our documentation."); + static_cast(out); // to get rid of unused errors + return UNINITIALIZED; #endif } @@ -115392,20 +115930,27 @@ class document { if constexpr (custom_deserializable) { return deserialize(*this, out); } else { -#endif // SIMDJSON_SUPPORTS_DESERIALIZATION - // Unless the simdjson library or the user provides an inline implementation, calling this method should - // immediately fail. - static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. " - "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " - "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), " - " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template." - " You may also add support for custom types, see our documentation."); + static_assert(!sizeof(T), "The get method with type T is not implemented by the simdjson library. " + "And you do not seem to have added support for it. Indeed, we have that " + "simdjson::custom_deserializable is false and the type T is not a default type " + "such as ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " + "int64_t, double, or bool."); static_cast(out); // to get rid of unused errors return UNINITIALIZED; -#if SIMDJSON_SUPPORTS_DESERIALIZATION } -#endif +#else // SIMDJSON_SUPPORTS_DESERIALIZATION + // Unless the simdjson library or the user provides an inline implementation, calling this method should + // immediately fail. + static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. " + "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " + "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), " + " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template." + " You may also add support for custom types, see our documentation."); + static_cast(out); // to get rid of unused errors + return UNINITIALIZED; +#endif // SIMDJSON_SUPPORTS_DESERIALIZATION } + /** @overload template error_code get(T &out) & noexcept */ template simdjson_deprecated simdjson_inline error_code get(T &out) && noexcept; @@ -115967,20 +116512,27 @@ class document_reference { if constexpr (custom_deserializable) { return deserialize(*this, out); } else { -#endif // SIMDJSON_SUPPORTS_DESERIALIZATION - // Unless the simdjson library or the user provides an inline implementation, calling this method should - // immediately fail. - static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. " - "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " - "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), " - " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template." - " You may also add support for custom types, see our documentation."); + static_assert(!sizeof(T), "The get method with type T is not implemented by the simdjson library. " + "And you do not seem to have added support for it. Indeed, we have that " + "simdjson::custom_deserializable is false and the type T is not a default type " + "such as ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " + "int64_t, double, or bool."); static_cast(out); // to get rid of unused errors return UNINITIALIZED; -#if SIMDJSON_SUPPORTS_DESERIALIZATION } -#endif +#else // SIMDJSON_SUPPORTS_DESERIALIZATION + // Unless the simdjson library or the user provides an inline implementation, calling this method should + // immediately fail. + static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. " + "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " + "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), " + " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template." + " You may also add support for custom types, see our documentation."); + static_cast(out); // to get rid of unused errors + return UNINITIALIZED; +#endif // SIMDJSON_SUPPORTS_DESERIALIZATION } + /** @overload template error_code get(T &out) & noexcept */ template simdjson_inline error_code get(T &out) && noexcept; simdjson_inline simdjson_result raw_json() noexcept; @@ -117155,6 +117707,16 @@ error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept { return SUCCESS; } +template + requires(!require_custom_serialization) +error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(std::is_nothrow_constructible_v) { + std::string_view str; + SIMDJSON_TRY(val.get_string().get(str)); + out = T{str}; + return SUCCESS; +} + + /** * STL containers have several constructors including one that takes a single * size argument. Thus, some compilers (Visual Studio) will not be able to @@ -117200,6 +117762,39 @@ error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) { } +/** + * We want to support std::map and std::unordered_map but only for + * string-keyed types. + */ + template + requires(!require_custom_serialization) +error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) { + using value_type = typename std::remove_cvref_t::mapped_type; + static_assert( + deserializable, + "The specified value type inside the container must itself be deserializable"); + static_assert( + std::is_default_constructible_v, + "The specified value type inside the container must default constructible."); + lasx::ondemand::object obj; + SIMDJSON_TRY(val.get_object().get(obj)); + for (auto field : obj) { + std::string_view key; + SIMDJSON_TRY(field.unescaped_key().get(key)); + value_type this_value; + SIMDJSON_TRY(field.value().get().get(this_value)); + [[maybe_unused]] std::pair result = out.emplace(key, this_value); + // unclear what to do if the key already exists + // if (result.second == false) { + // // key already exists + // } + } + (void)out; + return SUCCESS; +} + + + /** * This CPO (Customization Point Object) will help deserialize into @@ -122424,19 +123019,23 @@ simdjson_warn_unused simdjson_inline simdjson_result value_iterator::get } return result; } + simdjson_warn_unused simdjson_inline simdjson_result value_iterator::get_root_bool(bool check_trailing) noexcept { auto max_len = peek_root_length(); auto json = peek_root_scalar("bool"); - uint8_t tmpbuf[5+1+1]; // +1 for null termination - tmpbuf[5+1] = '\0'; // make sure that buffer is always null terminated. - if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 5+1)) { return incorrect_type_error("Not a boolean"); } - auto result = parse_bool(tmpbuf); - if(result.error() == SUCCESS) { - if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; } - advance_root_scalar("bool"); - } - return result; + // We have a boolean if we have either "true" or "false" and the next character is either + // a structural character or whitespace. We also check that the length is correct: + // "true" and "false" are 4 and 5 characters long, respectively. + bool value_true = (max_len >= 4 && !atomparsing::str4ncmp(json, "true") && + (max_len == 4 || jsoncharutils::is_structural_or_whitespace(json[4]))); + bool value_false = (max_len >= 5 && !atomparsing::str4ncmp(json, "false") && + (max_len == 5 || jsoncharutils::is_structural_or_whitespace(json[5]))); + if(value_true == false && value_false == false) { return incorrect_type_error("Not a boolean"); } + if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; } + advance_root_scalar("bool"); + return value_true; } + simdjson_inline simdjson_result value_iterator::is_root_null(bool check_trailing) noexcept { auto max_len = peek_root_length(); auto json = peek_root_scalar("null"); diff --git a/deps/sqlite/sqlite3.c b/deps/sqlite/sqlite3.c index 37b534afb2787c..58dc0e9208d7bd 100644 --- a/deps/sqlite/sqlite3.c +++ b/deps/sqlite/sqlite3.c @@ -1,6 +1,6 @@ /****************************************************************************** ** This file is an amalgamation of many separate C source files from SQLite -** version 3.49.1. By combining all the individual C code files into this +** version 3.50.0. By combining all the individual C code files into this ** single large file, the entire code can be compiled as a single translation ** unit. This allows many compilers to do optimizations that would not be ** possible if the files were compiled separately. Performance improvements @@ -18,7 +18,7 @@ ** separate file. This file contains only code for the core SQLite library. ** ** The content in this amalgamation comes from Fossil check-in -** 873d4e274b4988d260ba8354a9718324a1c2 with changes in files: +** dfc790f998f450d9c35e3ba1c8c89c17466c with changes in files: ** ** */ @@ -452,7 +452,7 @@ extern "C" { ** ** Since [version 3.6.18] ([dateof:3.6.18]), ** SQLite source code has been stored in the -** Fossil configuration management +** Fossil configuration management ** system. ^The SQLITE_SOURCE_ID macro evaluates to ** a string which identifies a particular check-in of SQLite ** within its configuration management system. ^The SQLITE_SOURCE_ID @@ -465,9 +465,9 @@ extern "C" { ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ -#define SQLITE_VERSION "3.49.1" -#define SQLITE_VERSION_NUMBER 3049001 -#define SQLITE_SOURCE_ID "2025-02-18 13:38:58 873d4e274b4988d260ba8354a9718324a1c26187a4ab4c1cc0227c03d0f10e70" +#define SQLITE_VERSION "3.50.0" +#define SQLITE_VERSION_NUMBER 3050000 +#define SQLITE_SOURCE_ID "2025-05-29 14:26:00 dfc790f998f450d9c35e3ba1c8c89c17466cb559f87b0239e4aab9d34e28f742" /* ** CAPI3REF: Run-Time Library Version Numbers @@ -1482,6 +1482,12 @@ struct sqlite3_io_methods { ** the value that M is to be set to. Before returning, the 32-bit signed ** integer is overwritten with the previous value of M. ** +**
  • [[SQLITE_FCNTL_BLOCK_ON_CONNECT]] +** The [SQLITE_FCNTL_BLOCK_ON_CONNECT] opcode is used to configure the +** VFS to block when taking a SHARED lock to connect to a wal mode database. +** This is used to implement the functionality associated with +** SQLITE_SETLK_BLOCK_ON_CONNECT. +** **
  • [[SQLITE_FCNTL_DATA_VERSION]] ** The [SQLITE_FCNTL_DATA_VERSION] opcode is used to detect changes to ** a database file. The argument is a pointer to a 32-bit unsigned integer. @@ -1578,6 +1584,7 @@ struct sqlite3_io_methods { #define SQLITE_FCNTL_CKSM_FILE 41 #define SQLITE_FCNTL_RESET_CACHE 42 #define SQLITE_FCNTL_NULL_IO 43 +#define SQLITE_FCNTL_BLOCK_ON_CONNECT 44 /* deprecated names */ #define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE @@ -2308,13 +2315,16 @@ struct sqlite3_mem_methods { ** ** [[SQLITE_CONFIG_LOOKASIDE]]
    SQLITE_CONFIG_LOOKASIDE
    **
    ^(The SQLITE_CONFIG_LOOKASIDE option takes two arguments that determine -** the default size of lookaside memory on each [database connection]. +** the default size of [lookaside memory] on each [database connection]. ** The first argument is the -** size of each lookaside buffer slot and the second is the number of -** slots allocated to each database connection.)^ ^(SQLITE_CONFIG_LOOKASIDE -** sets the default lookaside size. The [SQLITE_DBCONFIG_LOOKASIDE] -** option to [sqlite3_db_config()] can be used to change the lookaside -** configuration on individual connections.)^
    +** size of each lookaside buffer slot ("sz") and the second is the number of +** slots allocated to each database connection ("cnt").)^ +** ^(SQLITE_CONFIG_LOOKASIDE sets the default lookaside size. +** The [SQLITE_DBCONFIG_LOOKASIDE] option to [sqlite3_db_config()] can +** be used to change the lookaside configuration on individual connections.)^ +** The [-DSQLITE_DEFAULT_LOOKASIDE] option can be used to change the +** default lookaside configuration at compile-time. +** ** ** [[SQLITE_CONFIG_PCACHE2]]
    SQLITE_CONFIG_PCACHE2
    **
    ^(The SQLITE_CONFIG_PCACHE2 option takes a single argument which is @@ -2551,31 +2561,50 @@ struct sqlite3_mem_methods { ** [[SQLITE_DBCONFIG_LOOKASIDE]] **
    SQLITE_DBCONFIG_LOOKASIDE
    **
    The SQLITE_DBCONFIG_LOOKASIDE option is used to adjust the -** configuration of the lookaside memory allocator within a database +** configuration of the [lookaside memory allocator] within a database ** connection. ** The arguments to the SQLITE_DBCONFIG_LOOKASIDE option are not ** in the [DBCONFIG arguments|usual format]. ** The SQLITE_DBCONFIG_LOOKASIDE option takes three arguments, not two, ** so that a call to [sqlite3_db_config()] that uses SQLITE_DBCONFIG_LOOKASIDE ** should have a total of five parameters. -** ^The first argument (the third parameter to [sqlite3_db_config()] is a +**
      +**
    1. The first argument ("buf") is a ** pointer to a memory buffer to use for lookaside memory. -** ^The first argument after the SQLITE_DBCONFIG_LOOKASIDE verb -** may be NULL in which case SQLite will allocate the -** lookaside buffer itself using [sqlite3_malloc()]. ^The second argument is the -** size of each lookaside buffer slot. ^The third argument is the number of -** slots. The size of the buffer in the first argument must be greater than -** or equal to the product of the second and third arguments. The buffer -** must be aligned to an 8-byte boundary. ^If the second argument to -** SQLITE_DBCONFIG_LOOKASIDE is not a multiple of 8, it is internally -** rounded down to the next smaller multiple of 8. ^(The lookaside memory +** The first argument may be NULL in which case SQLite will allocate the +** lookaside buffer itself using [sqlite3_malloc()]. +**

    2. The second argument ("sz") is the +** size of each lookaside buffer slot. Lookaside is disabled if "sz" +** is less than 8. The "sz" argument should be a multiple of 8 less than +** 65536. If "sz" does not meet this constraint, it is reduced in size until +** it does. +**

    3. The third argument ("cnt") is the number of slots. Lookaside is disabled +** if "cnt"is less than 1. The "cnt" value will be reduced, if necessary, so +** that the product of "sz" and "cnt" does not exceed 2,147,418,112. The "cnt" +** parameter is usually chosen so that the product of "sz" and "cnt" is less +** than 1,000,000. +**

    +**

    If the "buf" argument is not NULL, then it must +** point to a memory buffer with a size that is greater than +** or equal to the product of "sz" and "cnt". +** The buffer must be aligned to an 8-byte boundary. +** The lookaside memory ** configuration for a database connection can only be changed when that ** connection is not currently using lookaside memory, or in other words -** when the "current value" returned by -** [sqlite3_db_status](D,[SQLITE_DBSTATUS_LOOKASIDE_USED],...) is zero. +** when the value returned by [SQLITE_DBSTATUS_LOOKASIDE_USED] is zero. ** Any attempt to change the lookaside memory configuration when lookaside ** memory is in use leaves the configuration unchanged and returns -** [SQLITE_BUSY].)^

    +** [SQLITE_BUSY]. +** If the "buf" argument is NULL and an attempt +** to allocate memory based on "sz" and "cnt" fails, then +** lookaside is silently disabled. +**

    +** The [SQLITE_CONFIG_LOOKASIDE] configuration option can be used to set the +** default lookaside configuration at initialization. The +** [-DSQLITE_DEFAULT_LOOKASIDE] option can be used to set the default lookaside +** configuration at compile-time. Typical values for lookaside are 1200 for +** "sz" and 40 to 100 for "cnt". +** ** ** [[SQLITE_DBCONFIG_ENABLE_FKEY]] **

    SQLITE_DBCONFIG_ENABLE_FKEY
    @@ -3312,6 +3341,44 @@ SQLITE_API int sqlite3_busy_handler(sqlite3*,int(*)(void*,int),void*); */ SQLITE_API int sqlite3_busy_timeout(sqlite3*, int ms); +/* +** CAPI3REF: Set the Setlk Timeout +** METHOD: sqlite3 +** +** This routine is only useful in SQLITE_ENABLE_SETLK_TIMEOUT builds. If +** the VFS supports blocking locks, it sets the timeout in ms used by +** eligible locks taken on wal mode databases by the specified database +** handle. In non-SQLITE_ENABLE_SETLK_TIMEOUT builds, or if the VFS does +** not support blocking locks, this function is a no-op. +** +** Passing 0 to this function disables blocking locks altogether. Passing +** -1 to this function requests that the VFS blocks for a long time - +** indefinitely if possible. The results of passing any other negative value +** are undefined. +** +** Internally, each SQLite database handle store two timeout values - the +** busy-timeout (used for rollback mode databases, or if the VFS does not +** support blocking locks) and the setlk-timeout (used for blocking locks +** on wal-mode databases). The sqlite3_busy_timeout() method sets both +** values, this function sets only the setlk-timeout value. Therefore, +** to configure separate busy-timeout and setlk-timeout values for a single +** database handle, call sqlite3_busy_timeout() followed by this function. +** +** Whenever the number of connections to a wal mode database falls from +** 1 to 0, the last connection takes an exclusive lock on the database, +** then checkpoints and deletes the wal file. While it is doing this, any +** new connection that tries to read from the database fails with an +** SQLITE_BUSY error. Or, if the SQLITE_SETLK_BLOCK_ON_CONNECT flag is +** passed to this API, the new connection blocks until the exclusive lock +** has been released. +*/ +SQLITE_API int sqlite3_setlk_timeout(sqlite3*, int ms, int flags); + +/* +** CAPI3REF: Flags for sqlite3_setlk_timeout() +*/ +#define SQLITE_SETLK_BLOCK_ON_CONNECT 0x01 + /* ** CAPI3REF: Convenience Routines For Running Queries ** METHOD: sqlite3 @@ -5427,7 +5494,7 @@ SQLITE_API const void *sqlite3_column_decltype16(sqlite3_stmt*,int); ** other than [SQLITE_ROW] before any subsequent invocation of ** sqlite3_step(). Failure to reset the prepared statement using ** [sqlite3_reset()] would result in an [SQLITE_MISUSE] return from -** sqlite3_step(). But after [version 3.6.23.1] ([dateof:3.6.23.1], +** sqlite3_step(). But after [version 3.6.23.1] ([dateof:3.6.23.1]), ** sqlite3_step() began ** calling [sqlite3_reset()] automatically in this circumstance rather ** than returning [SQLITE_MISUSE]. This is not considered a compatibility @@ -7323,6 +7390,8 @@ SQLITE_API int sqlite3_autovacuum_pages( ** ** ^The second argument is a pointer to the function to invoke when a ** row is updated, inserted or deleted in a rowid table. +** ^The update hook is disabled by invoking sqlite3_update_hook() +** with a NULL pointer as the second parameter. ** ^The first argument to the callback is a copy of the third argument ** to sqlite3_update_hook(). ** ^The second callback argument is one of [SQLITE_INSERT], [SQLITE_DELETE], @@ -11805,9 +11874,10 @@ SQLITE_API void sqlite3session_table_filter( ** is inserted while a session object is enabled, then later deleted while ** the same session object is disabled, no INSERT record will appear in the ** changeset, even though the delete took place while the session was disabled. -** Or, if one field of a row is updated while a session is disabled, and -** another field of the same row is updated while the session is enabled, the -** resulting changeset will contain an UPDATE change that updates both fields. +** Or, if one field of a row is updated while a session is enabled, and +** then another field of the same row is updated while the session is disabled, +** the resulting changeset will contain an UPDATE change that updates both +** fields. */ SQLITE_API int sqlite3session_changeset( sqlite3_session *pSession, /* Session object */ @@ -11879,8 +11949,9 @@ SQLITE_API sqlite3_int64 sqlite3session_changeset_size(sqlite3_session *pSession ** database zFrom the contents of the two compatible tables would be ** identical. ** -** It an error if database zFrom does not exist or does not contain the -** required compatible table. +** Unless the call to this function is a no-op as described above, it is an +** error if database zFrom does not exist or does not contain the required +** compatible table. ** ** If the operation is successful, SQLITE_OK is returned. Otherwise, an SQLite ** error code. In this case, if argument pzErrMsg is not NULL, *pzErrMsg @@ -12015,7 +12086,7 @@ SQLITE_API int sqlite3changeset_start_v2( ** The following flags may passed via the 4th parameter to ** [sqlite3changeset_start_v2] and [sqlite3changeset_start_v2_strm]: ** -**
    SQLITE_CHANGESETAPPLY_INVERT
    +**
    SQLITE_CHANGESETSTART_INVERT
    ** Invert the changeset while iterating through it. This is equivalent to ** inverting a changeset using sqlite3changeset_invert() before applying it. ** It is an error to specify this flag with a patchset. @@ -12330,19 +12401,6 @@ SQLITE_API int sqlite3changeset_concat( void **ppOut /* OUT: Buffer containing output changeset */ ); - -/* -** CAPI3REF: Upgrade the Schema of a Changeset/Patchset -*/ -SQLITE_API int sqlite3changeset_upgrade( - sqlite3 *db, - const char *zDb, - int nIn, const void *pIn, /* Input changeset */ - int *pnOut, void **ppOut /* OUT: Inverse of input */ -); - - - /* ** CAPI3REF: Changegroup Handle ** @@ -14090,14 +14148,22 @@ struct fts5_api { ** * Terms in the GROUP BY or ORDER BY clauses of a SELECT statement. ** * Terms in the VALUES clause of an INSERT statement ** -** The hard upper limit here is 32676. Most database people will +** The hard upper limit here is 32767. Most database people will ** tell you that in a well-normalized database, you usually should ** not have more than a dozen or so columns in any table. And if ** that is the case, there is no point in having more than a few ** dozen values in any of the other situations described above. +** +** An index can only have SQLITE_MAX_COLUMN columns from the user +** point of view, but the underlying b-tree that implements the index +** might have up to twice as many columns in a WITHOUT ROWID table, +** since must also store the primary key at the end. Hence the +** column count for Index is u16 instead of i16. */ -#ifndef SQLITE_MAX_COLUMN +#if !defined(SQLITE_MAX_COLUMN) # define SQLITE_MAX_COLUMN 2000 +#elif SQLITE_MAX_COLUMN>32767 +# error SQLITE_MAX_COLUMN may not exceed 32767 #endif /* @@ -14749,6 +14815,7 @@ struct HashElem { HashElem *next, *prev; /* Next and previous elements in the table */ void *data; /* Data associated with this element */ const char *pKey; /* Key associated with this element */ + unsigned int h; /* hash for pKey */ }; /* @@ -15109,7 +15176,17 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash*); ** ourselves. */ #ifndef offsetof -#define offsetof(STRUCTURE,FIELD) ((int)((char*)&((STRUCTURE*)0)->FIELD)) +#define offsetof(STRUCTURE,FIELD) ((size_t)((char*)&((STRUCTURE*)0)->FIELD)) +#endif + +/* +** Work around C99 "flex-array" syntax for pre-C99 compilers, so as +** to avoid complaints from -fsanitize=strict-bounds. +*/ +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) +# define FLEXARRAY +#else +# define FLEXARRAY 1 #endif /* @@ -15187,6 +15264,11 @@ typedef INT16_TYPE i16; /* 2-byte signed integer */ typedef UINT8_TYPE u8; /* 1-byte unsigned integer */ typedef INT8_TYPE i8; /* 1-byte signed integer */ +/* A bitfield type for use inside of structures. Always follow with :N where +** N is the number of bits. +*/ +typedef unsigned bft; /* Bit Field Type */ + /* ** SQLITE_MAX_U32 is a u64 constant that is the maximum u64 value ** that can be stored in a u32 without loss of data. The value @@ -15355,6 +15437,14 @@ typedef INT16_TYPE LogEst; #define LARGEST_UINT64 (0xffffffff|(((u64)0xffffffff)<<32)) #define SMALLEST_INT64 (((i64)-1) - LARGEST_INT64) +/* +** Macro SMXV(n) return the maximum value that can be held in variable n, +** assuming n is a signed integer type. UMXV(n) is similar for unsigned +** integer types. +*/ +#define SMXV(n) ((((i64)1)<<(sizeof(n)-1))-1) +#define UMXV(n) ((((i64)1)<<(sizeof(n)))-1) + /* ** Round up a number to the next larger multiple of 8. This is used ** to force 8-byte alignment on 64-bit architectures. @@ -17331,8 +17421,8 @@ SQLITE_PRIVATE int sqlite3NotPureFunc(sqlite3_context*); SQLITE_PRIVATE int sqlite3VdbeBytecodeVtabInit(sqlite3*); #endif -/* Use SQLITE_ENABLE_COMMENTS to enable generation of extra comments on -** each VDBE opcode. +/* Use SQLITE_ENABLE_EXPLAIN_COMMENTS to enable generation of extra +** comments on each VDBE opcode. ** ** Use the SQLITE_ENABLE_MODULE_COMMENTS macro to see some extra no-op ** comments in VDBE programs that show key decision points in the code @@ -18055,6 +18145,10 @@ struct sqlite3 { Savepoint *pSavepoint; /* List of active savepoints */ int nAnalysisLimit; /* Number of index rows to ANALYZE */ int busyTimeout; /* Busy handler timeout, in msec */ +#ifdef SQLITE_ENABLE_SETLK_TIMEOUT + int setlkTimeout; /* Blocking lock timeout, in msec. -1 -> inf. */ + int setlkFlags; /* Flags passed to setlk_timeout() */ +#endif int nSavepoint; /* Number of non-transaction savepoints */ int nStatement; /* Number of nested statement-transactions */ i64 nDeferredCons; /* Net deferred constraints this transaction. */ @@ -18733,6 +18827,7 @@ struct Table { } u; Trigger *pTrigger; /* List of triggers on this object */ Schema *pSchema; /* Schema that contains this table */ + u8 aHx[16]; /* Column aHt[K%sizeof(aHt)] might have hash K */ }; /* @@ -18866,9 +18961,13 @@ struct FKey { struct sColMap { /* Mapping of columns in pFrom to columns in zTo */ int iFrom; /* Index of column in pFrom */ char *zCol; /* Name of column in zTo. If NULL use PRIMARY KEY */ - } aCol[1]; /* One entry for each of nCol columns */ + } aCol[FLEXARRAY]; /* One entry for each of nCol columns */ }; +/* The size (in bytes) of an FKey object holding N columns. The answer +** does NOT include space to hold the zTo name. */ +#define SZ_FKEY(N) (offsetof(FKey,aCol)+(N)*sizeof(struct sColMap)) + /* ** SQLite supports many different ways to resolve a constraint ** error. ROLLBACK processing means that a constraint violation @@ -18930,9 +19029,12 @@ struct KeyInfo { u16 nAllField; /* Total columns, including key plus others */ sqlite3 *db; /* The database connection */ u8 *aSortFlags; /* Sort order for each column. */ - CollSeq *aColl[1]; /* Collating sequence for each term of the key */ + CollSeq *aColl[FLEXARRAY]; /* Collating sequence for each term of the key */ }; +/* The size (in bytes) of a KeyInfo object with up to N fields */ +#define SZ_KEYINFO(N) (offsetof(KeyInfo,aColl) + (N)*sizeof(CollSeq*)) + /* ** Allowed bit values for entries in the KeyInfo.aSortFlags[] array. */ @@ -19052,7 +19154,7 @@ struct Index { Pgno tnum; /* DB Page containing root of this index */ LogEst szIdxRow; /* Estimated average row size in bytes */ u16 nKeyCol; /* Number of columns forming the key */ - u16 nColumn; /* Number of columns stored in the index */ + u16 nColumn; /* Nr columns in btree. Can be 2*Table.nCol */ u8 onError; /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */ unsigned idxType:2; /* 0:Normal 1:UNIQUE, 2:PRIMARY KEY, 3:IPK */ unsigned bUnordered:1; /* Use this index for == or IN queries only */ @@ -19061,9 +19163,9 @@ struct Index { unsigned isCovering:1; /* True if this is a covering index */ unsigned noSkipScan:1; /* Do not try to use skip-scan if true */ unsigned hasStat1:1; /* aiRowLogEst values come from sqlite_stat1 */ - unsigned bLowQual:1; /* sqlite_stat1 says this is a low-quality index */ unsigned bNoQuery:1; /* Do not use this index to optimize queries */ unsigned bAscKeyBug:1; /* True if the bba7b69f9849b5bf bug applies */ + unsigned bIdxRowid:1; /* One or more of the index keys is the ROWID */ unsigned bHasVCol:1; /* Index references one or more VIRTUAL columns */ unsigned bHasExpr:1; /* Index contains an expression, either a literal ** expression, or a reference to a VIRTUAL column */ @@ -19390,10 +19492,10 @@ struct Expr { /* Macros can be used to test, set, or clear bits in the ** Expr.flags field. */ -#define ExprHasProperty(E,P) (((E)->flags&(P))!=0) -#define ExprHasAllProperty(E,P) (((E)->flags&(P))==(P)) -#define ExprSetProperty(E,P) (E)->flags|=(P) -#define ExprClearProperty(E,P) (E)->flags&=~(P) +#define ExprHasProperty(E,P) (((E)->flags&(u32)(P))!=0) +#define ExprHasAllProperty(E,P) (((E)->flags&(u32)(P))==(u32)(P)) +#define ExprSetProperty(E,P) (E)->flags|=(u32)(P) +#define ExprClearProperty(E,P) (E)->flags&=~(u32)(P) #define ExprAlwaysTrue(E) (((E)->flags&(EP_OuterON|EP_IsTrue))==EP_IsTrue) #define ExprAlwaysFalse(E) (((E)->flags&(EP_OuterON|EP_IsFalse))==EP_IsFalse) #define ExprIsFullSize(E) (((E)->flags&(EP_Reduced|EP_TokenOnly))==0) @@ -19505,9 +19607,14 @@ struct ExprList { int iConstExprReg; /* Register in which Expr value is cached. Used only ** by Parse.pConstExpr */ } u; - } a[1]; /* One slot for each expression in the list */ + } a[FLEXARRAY]; /* One slot for each expression in the list */ }; +/* The size (in bytes) of an ExprList object that is big enough to hold +** as many as N expressions. */ +#define SZ_EXPRLIST(N) \ + (offsetof(ExprList,a) + (N)*sizeof(struct ExprList_item)) + /* ** Allowed values for Expr.a.eEName */ @@ -19535,9 +19642,12 @@ struct IdList { int nId; /* Number of identifiers on the list */ struct IdList_item { char *zName; /* Name of the identifier */ - } a[1]; + } a[FLEXARRAY]; }; +/* The size (in bytes) of an IdList object that can hold up to N IDs. */ +#define SZ_IDLIST(N) (offsetof(IdList,a)+(N)*sizeof(struct IdList_item)) + /* ** Allowed values for IdList.eType, which determines which value of the a.u4 ** is valid. @@ -19657,11 +19767,19 @@ struct OnOrUsing { ** */ struct SrcList { - int nSrc; /* Number of tables or subqueries in the FROM clause */ - u32 nAlloc; /* Number of entries allocated in a[] below */ - SrcItem a[1]; /* One entry for each identifier on the list */ + int nSrc; /* Number of tables or subqueries in the FROM clause */ + u32 nAlloc; /* Number of entries allocated in a[] below */ + SrcItem a[FLEXARRAY]; /* One entry for each identifier on the list */ }; +/* Size (in bytes) of a SrcList object that can hold as many as N +** SrcItem objects. */ +#define SZ_SRCLIST(N) (offsetof(SrcList,a)+(N)*sizeof(SrcItem)) + +/* Size (in bytes( of a SrcList object that holds 1 SrcItem. This is a +** special case of SZ_SRCITEM(1) that comes up often. */ +#define SZ_SRCLIST_1 (offsetof(SrcList,a)+sizeof(SrcItem)) + /* ** Permitted values of the SrcList.a.jointype field */ @@ -20130,25 +20248,32 @@ struct Parse { char *zErrMsg; /* An error message */ Vdbe *pVdbe; /* An engine for executing database bytecode */ int rc; /* Return code from execution */ - u8 colNamesSet; /* TRUE after OP_ColumnName has been issued to pVdbe */ - u8 checkSchema; /* Causes schema cookie check after an error */ + LogEst nQueryLoop; /* Est number of iterations of a query (10*log2(N)) */ u8 nested; /* Number of nested calls to the parser/code generator */ u8 nTempReg; /* Number of temporary registers in aTempReg[] */ u8 isMultiWrite; /* True if statement may modify/insert multiple rows */ u8 mayAbort; /* True if statement may throw an ABORT exception */ u8 hasCompound; /* Need to invoke convertCompoundSelectToSubquery() */ - u8 okConstFactor; /* OK to factor out constants */ u8 disableLookaside; /* Number of times lookaside has been disabled */ u8 prepFlags; /* SQLITE_PREPARE_* flags */ u8 withinRJSubrtn; /* Nesting level for RIGHT JOIN body subroutines */ - u8 bHasWith; /* True if statement contains WITH */ u8 mSubrtnSig; /* mini Bloom filter on available SubrtnSig.selId */ + u8 eTriggerOp; /* TK_UPDATE, TK_INSERT or TK_DELETE */ + u8 bReturning; /* Coding a RETURNING trigger */ + u8 eOrconf; /* Default ON CONFLICT policy for trigger steps */ + u8 disableTriggers; /* True to disable triggers */ #if defined(SQLITE_DEBUG) || defined(SQLITE_COVERAGE_TEST) u8 earlyCleanup; /* OOM inside sqlite3ParserAddCleanup() */ #endif #ifdef SQLITE_DEBUG u8 ifNotExists; /* Might be true if IF NOT EXISTS. Assert()s only */ + u8 isCreate; /* CREATE TABLE, INDEX, or VIEW (but not TRIGGER) + ** and ALTER TABLE ADD COLUMN. */ #endif + bft colNamesSet :1; /* TRUE after OP_ColumnName has been issued to pVdbe */ + bft bHasWith :1; /* True if statement contains WITH */ + bft okConstFactor :1; /* OK to factor out constants */ + bft checkSchema :1; /* Causes schema cookie check after an error */ int nRangeReg; /* Size of the temporary register block */ int iRangeReg; /* First register in temporary register block */ int nErr; /* Number of errors seen */ @@ -20163,12 +20288,9 @@ struct Parse { ExprList *pConstExpr;/* Constant expressions */ IndexedExpr *pIdxEpr;/* List of expressions used by active indexes */ IndexedExpr *pIdxPartExpr; /* Exprs constrained by index WHERE clauses */ - Token constraintName;/* Name of the constraint currently being parsed */ yDbMask writeMask; /* Start a write transaction on these databases */ yDbMask cookieMask; /* Bitmask of schema verified databases */ - int regRowid; /* Register holding rowid of CREATE TABLE entry */ - int regRoot; /* Register holding root page number for new objects */ - int nMaxArg; /* Max args passed to user function by sub-program */ + int nMaxArg; /* Max args to xUpdate and xFilter vtab methods */ int nSelect; /* Number of SELECT stmts. Counter for Select.selId */ #ifndef SQLITE_OMIT_PROGRESS_CALLBACK u32 nProgressSteps; /* xProgress steps taken during sqlite3_prepare() */ @@ -20182,17 +20304,6 @@ struct Parse { Table *pTriggerTab; /* Table triggers are being coded for */ TriggerPrg *pTriggerPrg; /* Linked list of coded triggers */ ParseCleanup *pCleanup; /* List of cleanup operations to run after parse */ - union { - int addrCrTab; /* Address of OP_CreateBtree on CREATE TABLE */ - Returning *pReturning; /* The RETURNING clause */ - } u1; - u32 oldmask; /* Mask of old.* columns referenced */ - u32 newmask; /* Mask of new.* columns referenced */ - LogEst nQueryLoop; /* Est number of iterations of a query (10*log2(N)) */ - u8 eTriggerOp; /* TK_UPDATE, TK_INSERT or TK_DELETE */ - u8 bReturning; /* Coding a RETURNING trigger */ - u8 eOrconf; /* Default ON CONFLICT policy for trigger steps */ - u8 disableTriggers; /* True to disable triggers */ /************************************************************************** ** Fields above must be initialized to zero. The fields that follow, @@ -20204,6 +20315,19 @@ struct Parse { int aTempReg[8]; /* Holding area for temporary registers */ Parse *pOuterParse; /* Outer Parse object when nested */ Token sNameToken; /* Token with unqualified schema object name */ + u32 oldmask; /* Mask of old.* columns referenced */ + u32 newmask; /* Mask of new.* columns referenced */ + union { + struct { /* These fields available when isCreate is true */ + int addrCrTab; /* Address of OP_CreateBtree on CREATE TABLE */ + int regRowid; /* Register holding rowid of CREATE TABLE entry */ + int regRoot; /* Register holding root page for new objects */ + Token constraintName; /* Name of the constraint currently being parsed */ + } cr; + struct { /* These fields available to all other statements */ + Returning *pReturning; /* The RETURNING clause */ + } d; + } u1; /************************************************************************ ** Above is constant between recursions. Below is reset before and after @@ -20719,9 +20843,13 @@ struct With { int nCte; /* Number of CTEs in the WITH clause */ int bView; /* Belongs to the outermost Select of a view */ With *pOuter; /* Containing WITH clause, or NULL */ - Cte a[1]; /* For each CTE in the WITH clause.... */ + Cte a[FLEXARRAY]; /* For each CTE in the WITH clause.... */ }; +/* The size (in bytes) of a With object that can hold as many +** as N different CTEs. */ +#define SZ_WITH(N) (offsetof(With,a) + (N)*sizeof(Cte)) + /* ** The Cte object is not guaranteed to persist for the entire duration ** of code generation. (The query flattener or other parser tree @@ -20750,9 +20878,13 @@ struct DbClientData { DbClientData *pNext; /* Next in a linked list */ void *pData; /* The data */ void (*xDestructor)(void*); /* Destructor. Might be NULL */ - char zName[1]; /* Name of this client data. MUST BE LAST */ + char zName[FLEXARRAY]; /* Name of this client data. MUST BE LAST */ }; +/* The size (in bytes) of a DbClientData object that can has a name +** that is N bytes long, including the zero-terminator. */ +#define SZ_DBCLIENTDATA(N) (offsetof(DbClientData,zName)+(N)) + #ifdef SQLITE_DEBUG /* ** An instance of the TreeView object is used for printing the content of @@ -21195,7 +21327,7 @@ SQLITE_PRIVATE void sqlite3SubqueryColumnTypes(Parse*,Table*,Select*,char); SQLITE_PRIVATE Table *sqlite3ResultSetOfSelect(Parse*,Select*,char); SQLITE_PRIVATE void sqlite3OpenSchemaTable(Parse *, int); SQLITE_PRIVATE Index *sqlite3PrimaryKeyIndex(Table*); -SQLITE_PRIVATE i16 sqlite3TableColumnToIndex(Index*, i16); +SQLITE_PRIVATE int sqlite3TableColumnToIndex(Index*, int); #ifdef SQLITE_OMIT_GENERATED_COLUMNS # define sqlite3TableColumnToStorage(T,X) (X) /* No-op pass-through */ # define sqlite3StorageColumnToTable(T,X) (X) /* No-op pass-through */ @@ -21293,7 +21425,7 @@ SQLITE_PRIVATE void sqlite3SrcListAssignCursors(Parse*, SrcList*); SQLITE_PRIVATE void sqlite3IdListDelete(sqlite3*, IdList*); SQLITE_PRIVATE void sqlite3ClearOnOrUsing(sqlite3*, OnOrUsing*); SQLITE_PRIVATE void sqlite3SrcListDelete(sqlite3*, SrcList*); -SQLITE_PRIVATE Index *sqlite3AllocateIndexObject(sqlite3*,i16,int,char**); +SQLITE_PRIVATE Index *sqlite3AllocateIndexObject(sqlite3*,int,int,char**); SQLITE_PRIVATE void sqlite3CreateIndex(Parse*,Token*,Token*,SrcList*,ExprList*,int,Token*, Expr*, int, int, u8); SQLITE_PRIVATE void sqlite3DropIndex(Parse*, SrcList*, int); @@ -21429,7 +21561,8 @@ SQLITE_PRIVATE Select *sqlite3SelectDup(sqlite3*,const Select*,int); SQLITE_PRIVATE FuncDef *sqlite3FunctionSearch(int,const char*); SQLITE_PRIVATE void sqlite3InsertBuiltinFuncs(FuncDef*,int); SQLITE_PRIVATE FuncDef *sqlite3FindFunction(sqlite3*,const char*,int,u8,u8); -SQLITE_PRIVATE void sqlite3QuoteValue(StrAccum*,sqlite3_value*); +SQLITE_PRIVATE void sqlite3QuoteValue(StrAccum*,sqlite3_value*,int); +SQLITE_PRIVATE int sqlite3AppendOneUtf8Character(char*, u32); SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void); SQLITE_PRIVATE void sqlite3RegisterDateTimeFunctions(void); SQLITE_PRIVATE void sqlite3RegisterJsonFunctions(void); @@ -22294,6 +22427,9 @@ static const char * const sqlite3azCompileOpt[] = { #ifdef SQLITE_BUG_COMPATIBLE_20160819 "BUG_COMPATIBLE_20160819", #endif +#ifdef SQLITE_BUG_COMPATIBLE_20250510 + "BUG_COMPATIBLE_20250510", +#endif #ifdef SQLITE_CASE_SENSITIVE_LIKE "CASE_SENSITIVE_LIKE", #endif @@ -22530,6 +22666,9 @@ static const char * const sqlite3azCompileOpt[] = { #ifdef SQLITE_ENABLE_SESSION "ENABLE_SESSION", #endif +#ifdef SQLITE_ENABLE_SETLK_TIMEOUT + "ENABLE_SETLK_TIMEOUT", +#endif #ifdef SQLITE_ENABLE_SNAPSHOT "ENABLE_SNAPSHOT", #endif @@ -22584,6 +22723,9 @@ static const char * const sqlite3azCompileOpt[] = { #ifdef SQLITE_EXTRA_INIT "EXTRA_INIT=" CTIMEOPT_VAL(SQLITE_EXTRA_INIT), #endif +#ifdef SQLITE_EXTRA_INIT_MUTEXED + "EXTRA_INIT_MUTEXED=" CTIMEOPT_VAL(SQLITE_EXTRA_INIT_MUTEXED), +#endif #ifdef SQLITE_EXTRA_SHUTDOWN "EXTRA_SHUTDOWN=" CTIMEOPT_VAL(SQLITE_EXTRA_SHUTDOWN), #endif @@ -23568,12 +23710,19 @@ struct VdbeCursor { #endif VdbeTxtBlbCache *pCache; /* Cache of large TEXT or BLOB values */ - /* 2*nField extra array elements allocated for aType[], beyond the one - ** static element declared in the structure. nField total array slots for - ** aType[] and nField+1 array slots for aOffset[] */ - u32 aType[1]; /* Type values record decode. MUST BE LAST */ + /* Space is allocated for aType to hold at least 2*nField+1 entries: + ** nField slots for aType[] and nField+1 array slots for aOffset[] */ + u32 aType[FLEXARRAY]; /* Type values record decode. MUST BE LAST */ }; +/* +** The size (in bytes) of a VdbeCursor object that has an nField value of N +** or less. The value of SZ_VDBECURSOR(n) is guaranteed to be a multiple +** of 8. +*/ +#define SZ_VDBECURSOR(N) \ + (ROUND8(offsetof(VdbeCursor,aType)) + ((N)+1)*sizeof(u64)) + /* Return true if P is a null-only cursor */ #define IsNullCursor(P) \ @@ -23830,13 +23979,16 @@ struct sqlite3_context { u8 enc; /* Encoding to use for results */ u8 skipFlag; /* Skip accumulator loading if true */ u16 argc; /* Number of arguments */ - sqlite3_value *argv[1]; /* Argument set */ + sqlite3_value *argv[FLEXARRAY]; /* Argument set */ }; -/* A bitfield type for use inside of structures. Always follow with :N where -** N is the number of bits. +/* +** The size (in bytes) of an sqlite3_context object that holds N +** argv[] arguments. */ -typedef unsigned bft; /* Bit Field Type */ +#define SZ_CONTEXT(N) \ + (offsetof(sqlite3_context,argv)+(N)*sizeof(sqlite3_value*)) + /* The ScanStatus object holds a single value for the ** sqlite3_stmt_scanstatus() interface. @@ -23897,7 +24049,7 @@ struct Vdbe { i64 nStmtDefCons; /* Number of def. constraints when stmt started */ i64 nStmtDefImmCons; /* Number of def. imm constraints when stmt started */ Mem *aMem; /* The memory locations */ - Mem **apArg; /* Arguments to currently executing user function */ + Mem **apArg; /* Arguments xUpdate and xFilter vtab methods */ VdbeCursor **apCsr; /* One element of this array for each open cursor */ Mem *aVar; /* Values for the OP_Variable opcode. */ @@ -23917,6 +24069,7 @@ struct Vdbe { #ifdef SQLITE_DEBUG int rcApp; /* errcode set by sqlite3_result_error_code() */ u32 nWrite; /* Number of write operations that have occurred */ + int napArg; /* Size of the apArg[] array */ #endif u16 nResColumn; /* Number of columns in one row of the result set */ u16 nResAlloc; /* Column slots allocated to aColName[] */ @@ -23969,7 +24122,7 @@ struct PreUpdate { VdbeCursor *pCsr; /* Cursor to read old values from */ int op; /* One of SQLITE_INSERT, UPDATE, DELETE */ u8 *aRecord; /* old.* database record */ - KeyInfo keyinfo; + KeyInfo *pKeyinfo; /* Key information */ UnpackedRecord *pUnpacked; /* Unpacked version of aRecord[] */ UnpackedRecord *pNewUnpacked; /* Unpacked version of new.* record */ int iNewReg; /* Register for new.* values */ @@ -23981,6 +24134,7 @@ struct PreUpdate { Table *pTab; /* Schema object being updated */ Index *pPk; /* PK index if pTab is WITHOUT ROWID */ sqlite3_value **apDflt; /* Array of default values, if required */ + u8 keyinfoSpace[SZ_KEYINFO(0)]; /* Space to hold pKeyinfo[0] content */ }; /* @@ -24347,8 +24501,9 @@ SQLITE_PRIVATE int sqlite3LookasideUsed(sqlite3 *db, int *pHighwater){ nInit += countLookasideSlots(db->lookaside.pSmallInit); nFree += countLookasideSlots(db->lookaside.pSmallFree); #endif /* SQLITE_OMIT_TWOSIZE_LOOKASIDE */ - if( pHighwater ) *pHighwater = db->lookaside.nSlot - nInit; - return db->lookaside.nSlot - (nInit+nFree); + assert( db->lookaside.nSlot >= nInit+nFree ); + if( pHighwater ) *pHighwater = (int)(db->lookaside.nSlot - nInit); + return (int)(db->lookaside.nSlot - (nInit+nFree)); } /* @@ -24401,7 +24556,7 @@ SQLITE_API int sqlite3_db_status( assert( (op-SQLITE_DBSTATUS_LOOKASIDE_HIT)>=0 ); assert( (op-SQLITE_DBSTATUS_LOOKASIDE_HIT)<3 ); *pCurrent = 0; - *pHighwater = db->lookaside.anStat[op - SQLITE_DBSTATUS_LOOKASIDE_HIT]; + *pHighwater = (int)db->lookaside.anStat[op-SQLITE_DBSTATUS_LOOKASIDE_HIT]; if( resetFlag ){ db->lookaside.anStat[op - SQLITE_DBSTATUS_LOOKASIDE_HIT] = 0; } @@ -25913,7 +26068,7 @@ static int daysAfterMonday(DateTime *pDate){ ** In other words, return the day of the week according ** to this code: ** -** 0=Sunday, 1=Monday, 2=Tues, ..., 6=Saturday +** 0=Sunday, 1=Monday, 2=Tuesday, ..., 6=Saturday */ static int daysAfterSunday(DateTime *pDate){ assert( pDate->validJD ); @@ -30122,6 +30277,8 @@ SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3DefaultMutex(void){ #ifdef __CYGWIN__ # include +# include /* amalgamator: dontcache */ +# include /* amalgamator: dontcache */ # include /* amalgamator: dontcache */ #endif @@ -31516,17 +31673,17 @@ SQLITE_PRIVATE int sqlite3ApiExit(sqlite3* db, int rc){ #define etPERCENT 7 /* Percent symbol. %% */ #define etCHARX 8 /* Characters. %c */ /* The rest are extensions, not normally found in printf() */ -#define etSQLESCAPE 9 /* Strings with '\'' doubled. %q */ -#define etSQLESCAPE2 10 /* Strings with '\'' doubled and enclosed in '', - NULL pointers replaced by SQL NULL. %Q */ -#define etTOKEN 11 /* a pointer to a Token structure */ -#define etSRCITEM 12 /* a pointer to a SrcItem */ -#define etPOINTER 13 /* The %p conversion */ -#define etSQLESCAPE3 14 /* %w -> Strings with '\"' doubled */ -#define etORDINAL 15 /* %r -> 1st, 2nd, 3rd, 4th, etc. English only */ -#define etDECIMAL 16 /* %d or %u, but not %x, %o */ +#define etESCAPE_q 9 /* Strings with '\'' doubled. %q */ +#define etESCAPE_Q 10 /* Strings with '\'' doubled and enclosed in '', + NULL pointers replaced by SQL NULL. %Q */ +#define etTOKEN 11 /* a pointer to a Token structure */ +#define etSRCITEM 12 /* a pointer to a SrcItem */ +#define etPOINTER 13 /* The %p conversion */ +#define etESCAPE_w 14 /* %w -> Strings with '\"' doubled */ +#define etORDINAL 15 /* %r -> 1st, 2nd, 3rd, 4th, etc. English only */ +#define etDECIMAL 16 /* %d or %u, but not %x, %o */ -#define etINVALID 17 /* Any unrecognized conversion type */ +#define etINVALID 17 /* Any unrecognized conversion type */ /* @@ -31565,9 +31722,9 @@ static const et_info fmtinfo[] = { { 's', 0, 4, etSTRING, 0, 0 }, { 'g', 0, 1, etGENERIC, 30, 0 }, { 'z', 0, 4, etDYNSTRING, 0, 0 }, - { 'q', 0, 4, etSQLESCAPE, 0, 0 }, - { 'Q', 0, 4, etSQLESCAPE2, 0, 0 }, - { 'w', 0, 4, etSQLESCAPE3, 0, 0 }, + { 'q', 0, 4, etESCAPE_q, 0, 0 }, + { 'Q', 0, 4, etESCAPE_Q, 0, 0 }, + { 'w', 0, 4, etESCAPE_w, 0, 0 }, { 'c', 0, 0, etCHARX, 0, 0 }, { 'o', 8, 0, etRADIX, 0, 2 }, { 'u', 10, 0, etDECIMAL, 0, 0 }, @@ -32164,25 +32321,7 @@ SQLITE_API void sqlite3_str_vappendf( } }else{ unsigned int ch = va_arg(ap,unsigned int); - if( ch<0x00080 ){ - buf[0] = ch & 0xff; - length = 1; - }else if( ch<0x00800 ){ - buf[0] = 0xc0 + (u8)((ch>>6)&0x1f); - buf[1] = 0x80 + (u8)(ch & 0x3f); - length = 2; - }else if( ch<0x10000 ){ - buf[0] = 0xe0 + (u8)((ch>>12)&0x0f); - buf[1] = 0x80 + (u8)((ch>>6) & 0x3f); - buf[2] = 0x80 + (u8)(ch & 0x3f); - length = 3; - }else{ - buf[0] = 0xf0 + (u8)((ch>>18) & 0x07); - buf[1] = 0x80 + (u8)((ch>>12) & 0x3f); - buf[2] = 0x80 + (u8)((ch>>6) & 0x3f); - buf[3] = 0x80 + (u8)(ch & 0x3f); - length = 4; - } + length = sqlite3AppendOneUtf8Character(buf, ch); } if( precision>1 ){ i64 nPrior = 1; @@ -32262,22 +32401,31 @@ SQLITE_API void sqlite3_str_vappendf( while( ii>=0 ) if( (bufpt[ii--] & 0xc0)==0x80 ) width++; } break; - case etSQLESCAPE: /* %q: Escape ' characters */ - case etSQLESCAPE2: /* %Q: Escape ' and enclose in '...' */ - case etSQLESCAPE3: { /* %w: Escape " characters */ + case etESCAPE_q: /* %q: Escape ' characters */ + case etESCAPE_Q: /* %Q: Escape ' and enclose in '...' */ + case etESCAPE_w: { /* %w: Escape " characters */ i64 i, j, k, n; - int needQuote, isnull; + int needQuote = 0; char ch; - char q = ((xtype==etSQLESCAPE3)?'"':'\''); /* Quote character */ char *escarg; + char q; if( bArgList ){ escarg = getTextArg(pArgList); }else{ escarg = va_arg(ap,char*); } - isnull = escarg==0; - if( isnull ) escarg = (xtype==etSQLESCAPE2 ? "NULL" : "(NULL)"); + if( escarg==0 ){ + escarg = (xtype==etESCAPE_Q ? "NULL" : "(NULL)"); + }else if( xtype==etESCAPE_Q ){ + needQuote = 1; + } + if( xtype==etESCAPE_w ){ + q = '"'; + flag_alternateform = 0; + }else{ + q = '\''; + } /* For %q, %Q, and %w, the precision is the number of bytes (or ** characters if the ! flags is present) to use from the input. ** Because of the extra quoting characters inserted, the number @@ -32290,7 +32438,30 @@ SQLITE_API void sqlite3_str_vappendf( while( (escarg[i+1]&0xc0)==0x80 ){ i++; } } } - needQuote = !isnull && xtype==etSQLESCAPE2; + if( flag_alternateform ){ + /* For %#q, do unistr()-style backslash escapes for + ** all control characters, and for backslash itself. + ** For %#Q, do the same but only if there is at least + ** one control character. */ + u32 nBack = 0; + u32 nCtrl = 0; + for(k=0; ketBUFSIZE ){ bufpt = zExtra = printfTempBuf(pAccum, n); @@ -32299,13 +32470,41 @@ SQLITE_API void sqlite3_str_vappendf( bufpt = buf; } j = 0; - if( needQuote ) bufpt[j++] = q; + if( needQuote ){ + if( needQuote==2 ){ + memcpy(&bufpt[j], "unistr('", 8); + j += 8; + }else{ + bufpt[j++] = '\''; + } + } k = i; - for(i=0; i=0x10 ? '1' : '0'; + bufpt[j++] = "0123456789abcdef"[ch&0xf]; + } + } + }else{ + for(i=0; imxAlloc>0 && !isMalloced(p) ); - zText = sqlite3DbMallocRaw(p->db, p->nChar+1 ); + zText = sqlite3DbMallocRaw(p->db, 1+(u64)p->nChar ); if( zText ){ memcpy(zText, p->zText, p->nChar+1); p->printfFlags |= SQLITE_PRINTF_MALLOCED; @@ -32793,6 +32992,15 @@ SQLITE_API char *sqlite3_snprintf(int n, char *zBuf, const char *zFormat, ...){ return zBuf; } +/* Maximum size of an sqlite3_log() message. */ +#if defined(SQLITE_MAX_LOG_MESSAGE) + /* Leave the definition as supplied */ +#elif SQLITE_PRINT_BUF_SIZE*10>10000 +# define SQLITE_MAX_LOG_MESSAGE 10000 +#else +# define SQLITE_MAX_LOG_MESSAGE (SQLITE_PRINT_BUF_SIZE*10) +#endif + /* ** This is the routine that actually formats the sqlite3_log() message. ** We house it in a separate routine from sqlite3_log() to avoid using @@ -32809,7 +33017,7 @@ SQLITE_API char *sqlite3_snprintf(int n, char *zBuf, const char *zFormat, ...){ */ static void renderLogMsg(int iErrCode, const char *zFormat, va_list ap){ StrAccum acc; /* String accumulator */ - char zMsg[SQLITE_PRINT_BUF_SIZE*3]; /* Complete log message */ + char zMsg[SQLITE_MAX_LOG_MESSAGE]; /* Complete log message */ sqlite3StrAccumInit(&acc, 0, zMsg, sizeof(zMsg), 0); sqlite3_str_vappendf(&acc, zFormat, ap); @@ -34804,6 +35012,35 @@ static const unsigned char sqlite3Utf8Trans1[] = { } \ } +/* +** Write a single UTF8 character whose value is v into the +** buffer starting at zOut. zOut must be sized to hold at +** least four bytes. Return the number of bytes needed +** to encode the new character. +*/ +SQLITE_PRIVATE int sqlite3AppendOneUtf8Character(char *zOut, u32 v){ + if( v<0x00080 ){ + zOut[0] = (u8)(v & 0xff); + return 1; + } + if( v<0x00800 ){ + zOut[0] = 0xc0 + (u8)((v>>6) & 0x1f); + zOut[1] = 0x80 + (u8)(v & 0x3f); + return 2; + } + if( v<0x10000 ){ + zOut[0] = 0xe0 + (u8)((v>>12) & 0x0f); + zOut[1] = 0x80 + (u8)((v>>6) & 0x3f); + zOut[2] = 0x80 + (u8)(v & 0x3f); + return 3; + } + zOut[0] = 0xf0 + (u8)((v>>18) & 0x07); + zOut[1] = 0x80 + (u8)((v>>12) & 0x3f); + zOut[2] = 0x80 + (u8)((v>>6) & 0x3f); + zOut[3] = 0x80 + (u8)(v & 0x3f); + return 4; +} + /* ** Translate a single UTF-8 character. Return the unicode value. ** @@ -35225,7 +35462,7 @@ SQLITE_PRIVATE int sqlite3Utf16ByteLen(const void *zIn, int nByte, int nChar){ int n = 0; if( SQLITE_UTF16NATIVE==SQLITE_UTF16LE ) z++; - while( n=0xd8 && c<0xdc && z<=zEnd && z[0]>=0xdc && z[0]<0xe0 ) z += 2; @@ -36400,7 +36637,11 @@ SQLITE_PRIVATE void sqlite3FpDecode(FpDecode *p, double r, int iRound, int mxRou } p->z = &p->zBuf[i+1]; assert( i+p->n < sizeof(p->zBuf) ); - while( ALWAYS(p->n>0) && p->z[p->n-1]=='0' ){ p->n--; } + assert( p->n>0 ); + while( p->z[p->n-1]=='0' ){ + p->n--; + assert( p->n>0 ); + } } /* @@ -36905,7 +37146,7 @@ SQLITE_PRIVATE int sqlite3MulInt64(i64 *pA, i64 iB){ } /* -** Compute the absolute value of a 32-bit signed integer, of possible. Or +** Compute the absolute value of a 32-bit signed integer, if possible. Or ** if the integer has a value of -2147483648, return +2147483647 */ SQLITE_PRIVATE int sqlite3AbsInt32(int x){ @@ -37186,12 +37427,19 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash *pH){ */ static unsigned int strHash(const char *z){ unsigned int h = 0; - unsigned char c; - while( (c = (unsigned char)*z++)!=0 ){ /*OPTIMIZATION-IF-TRUE*/ + while( z[0] ){ /*OPTIMIZATION-IF-TRUE*/ /* Knuth multiplicative hashing. (Sorting & Searching, p. 510). ** 0x9e3779b1 is 2654435761 which is the closest prime number to - ** (2**32)*golden_ratio, where golden_ratio = (sqrt(5) - 1)/2. */ - h += sqlite3UpperToLower[c]; + ** (2**32)*golden_ratio, where golden_ratio = (sqrt(5) - 1)/2. + ** + ** Only bits 0xdf for ASCII and bits 0xbf for EBCDIC each octet are + ** hashed since the omitted bits determine the upper/lower case difference. + */ +#ifdef SQLITE_EBCDIC + h += 0xbf & (unsigned char)*(z++); +#else + h += 0xdf & (unsigned char)*(z++); +#endif h *= 0x9e3779b1; } return h; @@ -37264,9 +37512,8 @@ static int rehash(Hash *pH, unsigned int new_size){ pH->htsize = new_size = sqlite3MallocSize(new_ht)/sizeof(struct _ht); memset(new_ht, 0, new_size*sizeof(struct _ht)); for(elem=pH->first, pH->first=0; elem; elem = next_elem){ - unsigned int h = strHash(elem->pKey) % new_size; next_elem = elem->next; - insertElement(pH, &new_ht[h], elem); + insertElement(pH, &new_ht[elem->h % new_size], elem); } return 1; } @@ -37284,23 +37531,22 @@ static HashElem *findElementWithHash( HashElem *elem; /* Used to loop thru the element list */ unsigned int count; /* Number of elements left to test */ unsigned int h; /* The computed hash */ - static HashElem nullElement = { 0, 0, 0, 0 }; + static HashElem nullElement = { 0, 0, 0, 0, 0 }; + h = strHash(pKey); if( pH->ht ){ /*OPTIMIZATION-IF-TRUE*/ struct _ht *pEntry; - h = strHash(pKey) % pH->htsize; - pEntry = &pH->ht[h]; + pEntry = &pH->ht[h % pH->htsize]; elem = pEntry->chain; count = pEntry->count; }else{ - h = 0; elem = pH->first; count = pH->count; } if( pHash ) *pHash = h; while( count ){ assert( elem!=0 ); - if( sqlite3StrICmp(elem->pKey,pKey)==0 ){ + if( h==elem->h && sqlite3StrICmp(elem->pKey,pKey)==0 ){ return elem; } elem = elem->next; @@ -37312,10 +37558,9 @@ static HashElem *findElementWithHash( /* Remove a single entry from the hash table given a pointer to that ** element and a hash on the element's key. */ -static void removeElementGivenHash( +static void removeElement( Hash *pH, /* The pH containing "elem" */ - HashElem* elem, /* The element to be removed from the pH */ - unsigned int h /* Hash value for the element */ + HashElem *elem /* The element to be removed from the pH */ ){ struct _ht *pEntry; if( elem->prev ){ @@ -37327,7 +37572,7 @@ static void removeElementGivenHash( elem->next->prev = elem->prev; } if( pH->ht ){ - pEntry = &pH->ht[h]; + pEntry = &pH->ht[elem->h % pH->htsize]; if( pEntry->chain==elem ){ pEntry->chain = elem->next; } @@ -37378,7 +37623,7 @@ SQLITE_PRIVATE void *sqlite3HashInsert(Hash *pH, const char *pKey, void *data){ if( elem->data ){ void *old_data = elem->data; if( data==0 ){ - removeElementGivenHash(pH,elem,h); + removeElement(pH,elem); }else{ elem->data = data; elem->pKey = pKey; @@ -37389,15 +37634,13 @@ SQLITE_PRIVATE void *sqlite3HashInsert(Hash *pH, const char *pKey, void *data){ new_elem = (HashElem*)sqlite3Malloc( sizeof(HashElem) ); if( new_elem==0 ) return data; new_elem->pKey = pKey; + new_elem->h = h; new_elem->data = data; pH->count++; - if( pH->count>=10 && pH->count > 2*pH->htsize ){ - if( rehash(pH, pH->count*2) ){ - assert( pH->htsize>0 ); - h = strHash(pKey) % pH->htsize; - } + if( pH->count>=5 && pH->count > 2*pH->htsize ){ + rehash(pH, pH->count*3); } - insertElement(pH, pH->ht ? &pH->ht[h] : 0, new_elem); + insertElement(pH, pH->ht ? &pH->ht[new_elem->h % pH->htsize] : 0, new_elem); return 0; } @@ -38880,6 +39123,7 @@ struct unixFile { #endif #ifdef SQLITE_ENABLE_SETLK_TIMEOUT unsigned iBusyTimeout; /* Wait this many millisec on locks */ + int bBlockOnConnect; /* True to block for SHARED locks */ #endif #if OS_VXWORKS struct vxworksFileId *pId; /* Unique file ID */ @@ -40273,6 +40517,13 @@ static int unixFileLock(unixFile *pFile, struct flock *pLock){ rc = 0; } }else{ +#ifdef SQLITE_ENABLE_SETLK_TIMEOUT + if( pFile->bBlockOnConnect && pLock->l_type==F_RDLCK + && pLock->l_start==SHARED_FIRST && pLock->l_len==SHARED_SIZE + ){ + rc = osFcntl(pFile->h, F_SETLKW, pLock); + }else +#endif rc = osSetPosixAdvisoryLock(pFile->h, pLock, pFile); } return rc; @@ -42634,8 +42885,9 @@ static int unixFileControl(sqlite3_file *id, int op, void *pArg){ #ifdef SQLITE_ENABLE_SETLK_TIMEOUT case SQLITE_FCNTL_LOCK_TIMEOUT: { int iOld = pFile->iBusyTimeout; + int iNew = *(int*)pArg; #if SQLITE_ENABLE_SETLK_TIMEOUT==1 - pFile->iBusyTimeout = *(int*)pArg; + pFile->iBusyTimeout = iNew<0 ? 0x7FFFFFFF : (unsigned)iNew; #elif SQLITE_ENABLE_SETLK_TIMEOUT==2 pFile->iBusyTimeout = !!(*(int*)pArg); #else @@ -42644,7 +42896,12 @@ static int unixFileControl(sqlite3_file *id, int op, void *pArg){ *(int*)pArg = iOld; return SQLITE_OK; } -#endif + case SQLITE_FCNTL_BLOCK_ON_CONNECT: { + int iNew = *(int*)pArg; + pFile->bBlockOnConnect = iNew; + return SQLITE_OK; + } +#endif /* SQLITE_ENABLE_SETLK_TIMEOUT */ #if SQLITE_MAX_MMAP_SIZE>0 case SQLITE_FCNTL_MMAP_SIZE: { i64 newLimit = *(i64*)pArg; @@ -43627,7 +43884,7 @@ static int unixShmLock( ** ** It is not permitted to block on the RECOVER lock. */ -#ifdef SQLITE_ENABLE_SETLK_TIMEOUT +#if defined(SQLITE_ENABLE_SETLK_TIMEOUT) && defined(SQLITE_DEBUG) { u16 lockMask = (p->exclMask|p->sharedMask); assert( (flags & SQLITE_SHM_UNLOCK) || pDbFd->iBusyTimeout==0 || ( @@ -45436,7 +45693,7 @@ static int unixSleep(sqlite3_vfs *NotUsed, int microseconds){ /* Almost all modern unix systems support nanosleep(). But if you are ** compiling for one of the rare exceptions, you can use - ** -DHAVE_NANOSLEEP=0 (perhaps in conjuction with -DHAVE_USLEEP if + ** -DHAVE_NANOSLEEP=0 (perhaps in conjunction with -DHAVE_USLEEP if ** usleep() is available) in order to bypass the use of nanosleep() */ nanosleep(&sp, NULL); @@ -47157,8 +47414,18 @@ struct winFile { sqlite3_int64 mmapSize; /* Size of mapped region */ sqlite3_int64 mmapSizeMax; /* Configured FCNTL_MMAP_SIZE value */ #endif +#ifdef SQLITE_ENABLE_SETLK_TIMEOUT + DWORD iBusyTimeout; /* Wait this many millisec on locks */ + int bBlockOnConnect; +#endif }; +#ifdef SQLITE_ENABLE_SETLK_TIMEOUT +# define winFileBusyTimeout(pDbFd) pDbFd->iBusyTimeout +#else +# define winFileBusyTimeout(pDbFd) 0 +#endif + /* ** The winVfsAppData structure is used for the pAppData member for all of the ** Win32 VFS variants. @@ -47477,7 +47744,7 @@ static struct win_syscall { { "FileTimeToLocalFileTime", (SYSCALL)0, 0 }, #endif -#define osFileTimeToLocalFileTime ((BOOL(WINAPI*)(CONST FILETIME*, \ +#define osFileTimeToLocalFileTime ((BOOL(WINAPI*)(const FILETIME*, \ LPFILETIME))aSyscall[11].pCurrent) #if SQLITE_OS_WINCE @@ -47486,7 +47753,7 @@ static struct win_syscall { { "FileTimeToSystemTime", (SYSCALL)0, 0 }, #endif -#define osFileTimeToSystemTime ((BOOL(WINAPI*)(CONST FILETIME*, \ +#define osFileTimeToSystemTime ((BOOL(WINAPI*)(const FILETIME*, \ LPSYSTEMTIME))aSyscall[12].pCurrent) { "FlushFileBuffers", (SYSCALL)FlushFileBuffers, 0 }, @@ -47592,6 +47859,12 @@ static struct win_syscall { #define osGetFullPathNameW ((DWORD(WINAPI*)(LPCWSTR,DWORD,LPWSTR, \ LPWSTR*))aSyscall[25].pCurrent) +/* +** For GetLastError(), MSDN says: +** +** Minimum supported client: Windows XP [desktop apps | UWP apps] +** Minimum supported server: Windows Server 2003 [desktop apps | UWP apps] +*/ { "GetLastError", (SYSCALL)GetLastError, 0 }, #define osGetLastError ((DWORD(WINAPI*)(VOID))aSyscall[26].pCurrent) @@ -47760,7 +48033,7 @@ static struct win_syscall { { "LockFile", (SYSCALL)0, 0 }, #endif -#ifndef osLockFile +#if !defined(osLockFile) && defined(SQLITE_WIN32_HAS_ANSI) #define osLockFile ((BOOL(WINAPI*)(HANDLE,DWORD,DWORD,DWORD, \ DWORD))aSyscall[47].pCurrent) #endif @@ -47824,7 +48097,7 @@ static struct win_syscall { { "SystemTimeToFileTime", (SYSCALL)SystemTimeToFileTime, 0 }, -#define osSystemTimeToFileTime ((BOOL(WINAPI*)(CONST SYSTEMTIME*, \ +#define osSystemTimeToFileTime ((BOOL(WINAPI*)(const SYSTEMTIME*, \ LPFILETIME))aSyscall[56].pCurrent) #if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT @@ -47833,7 +48106,7 @@ static struct win_syscall { { "UnlockFile", (SYSCALL)0, 0 }, #endif -#ifndef osUnlockFile +#if !defined(osUnlockFile) && defined(SQLITE_WIN32_HAS_ANSI) #define osUnlockFile ((BOOL(WINAPI*)(HANDLE,DWORD,DWORD,DWORD, \ DWORD))aSyscall[57].pCurrent) #endif @@ -47874,11 +48147,13 @@ static struct win_syscall { #define osCreateEventExW ((HANDLE(WINAPI*)(LPSECURITY_ATTRIBUTES,LPCWSTR, \ DWORD,DWORD))aSyscall[62].pCurrent) -#if !SQLITE_OS_WINRT +/* +** For WaitForSingleObject(), MSDN says: +** +** Minimum supported client: Windows XP [desktop apps | UWP apps] +** Minimum supported server: Windows Server 2003 [desktop apps | UWP apps] +*/ { "WaitForSingleObject", (SYSCALL)WaitForSingleObject, 0 }, -#else - { "WaitForSingleObject", (SYSCALL)0, 0 }, -#endif #define osWaitForSingleObject ((DWORD(WINAPI*)(HANDLE, \ DWORD))aSyscall[63].pCurrent) @@ -48025,6 +48300,97 @@ static struct win_syscall { #define osFlushViewOfFile \ ((BOOL(WINAPI*)(LPCVOID,SIZE_T))aSyscall[79].pCurrent) +/* +** If SQLITE_ENABLE_SETLK_TIMEOUT is defined, we require CreateEvent() +** to implement blocking locks with timeouts. MSDN says: +** +** Minimum supported client: Windows XP [desktop apps | UWP apps] +** Minimum supported server: Windows Server 2003 [desktop apps | UWP apps] +*/ +#ifdef SQLITE_ENABLE_SETLK_TIMEOUT + { "CreateEvent", (SYSCALL)CreateEvent, 0 }, +#else + { "CreateEvent", (SYSCALL)0, 0 }, +#endif + +#define osCreateEvent ( \ + (HANDLE(WINAPI*) (LPSECURITY_ATTRIBUTES,BOOL,BOOL,LPCSTR)) \ + aSyscall[80].pCurrent \ +) + +/* +** If SQLITE_ENABLE_SETLK_TIMEOUT is defined, we require CancelIo() +** for the case where a timeout expires and a lock request must be +** cancelled. +** +** Minimum supported client: Windows XP [desktop apps | UWP apps] +** Minimum supported server: Windows Server 2003 [desktop apps | UWP apps] +*/ +#ifdef SQLITE_ENABLE_SETLK_TIMEOUT + { "CancelIo", (SYSCALL)CancelIo, 0 }, +#else + { "CancelIo", (SYSCALL)0, 0 }, +#endif + +#define osCancelIo ((BOOL(WINAPI*)(HANDLE))aSyscall[81].pCurrent) + +#if defined(SQLITE_WIN32_HAS_WIDE) && defined(_WIN32) + { "GetModuleHandleW", (SYSCALL)GetModuleHandleW, 0 }, +#else + { "GetModuleHandleW", (SYSCALL)0, 0 }, +#endif + +#define osGetModuleHandleW ((HMODULE(WINAPI*)(LPCWSTR))aSyscall[82].pCurrent) + +#ifndef _WIN32 + { "getenv", (SYSCALL)getenv, 0 }, +#else + { "getenv", (SYSCALL)0, 0 }, +#endif + +#define osGetenv ((const char *(*)(const char *))aSyscall[83].pCurrent) + +#ifndef _WIN32 + { "getcwd", (SYSCALL)getcwd, 0 }, +#else + { "getcwd", (SYSCALL)0, 0 }, +#endif + +#define osGetcwd ((char*(*)(char*,size_t))aSyscall[84].pCurrent) + +#ifndef _WIN32 + { "readlink", (SYSCALL)readlink, 0 }, +#else + { "readlink", (SYSCALL)0, 0 }, +#endif + +#define osReadlink ((ssize_t(*)(const char*,char*,size_t))aSyscall[85].pCurrent) + +#ifndef _WIN32 + { "lstat", (SYSCALL)lstat, 0 }, +#else + { "lstat", (SYSCALL)0, 0 }, +#endif + +#define osLstat ((int(*)(const char*,struct stat*))aSyscall[86].pCurrent) + +#ifndef _WIN32 + { "__errno", (SYSCALL)__errno, 0 }, +#else + { "__errno", (SYSCALL)0, 0 }, +#endif + +#define osErrno (*((int*(*)(void))aSyscall[87].pCurrent)()) + +#ifndef _WIN32 + { "cygwin_conv_path", (SYSCALL)cygwin_conv_path, 0 }, +#else + { "cygwin_conv_path", (SYSCALL)0, 0 }, +#endif + +#define osCygwin_conv_path ((size_t(*)(unsigned int, \ + const void *, void *, size_t))aSyscall[88].pCurrent) + }; /* End of the overrideable system calls */ /* @@ -48198,6 +48564,7 @@ SQLITE_API int sqlite3_win32_reset_heap(){ } #endif /* SQLITE_WIN32_MALLOC */ +#ifdef _WIN32 /* ** This function outputs the specified (ANSI) string to the Win32 debugger ** (if available). @@ -48240,6 +48607,7 @@ SQLITE_API void sqlite3_win32_write_debug(const char *zBuf, int nBuf){ } #endif } +#endif /* _WIN32 */ /* ** The following routine suspends the current thread for at least ms @@ -48323,7 +48691,9 @@ SQLITE_API int sqlite3_win32_is_nt(void){ } return osInterlockedCompareExchange(&sqlite3_os_type, 2, 2)==2; #elif SQLITE_TEST - return osInterlockedCompareExchange(&sqlite3_os_type, 2, 2)==2; + return osInterlockedCompareExchange(&sqlite3_os_type, 2, 2)==2 + || osInterlockedCompareExchange(&sqlite3_os_type, 0, 0)==0 + ; #else /* ** NOTE: All sub-platforms where the GetVersionEx[AW] functions are @@ -48538,6 +48908,7 @@ SQLITE_PRIVATE void sqlite3MemSetDefault(void){ } #endif /* SQLITE_WIN32_MALLOC */ +#ifdef _WIN32 /* ** Convert a UTF-8 string to Microsoft Unicode. ** @@ -48563,6 +48934,7 @@ static LPWSTR winUtf8ToUnicode(const char *zText){ } return zWideText; } +#endif /* _WIN32 */ /* ** Convert a Microsoft Unicode string to UTF-8. @@ -48597,28 +48969,29 @@ static char *winUnicodeToUtf8(LPCWSTR zWideText){ ** Space to hold the returned string is obtained from sqlite3_malloc(). */ static LPWSTR winMbcsToUnicode(const char *zText, int useAnsi){ - int nByte; + int nWideChar; LPWSTR zMbcsText; int codepage = useAnsi ? CP_ACP : CP_OEMCP; - nByte = osMultiByteToWideChar(codepage, 0, zText, -1, NULL, - 0)*sizeof(WCHAR); - if( nByte==0 ){ + nWideChar = osMultiByteToWideChar(codepage, 0, zText, -1, NULL, + 0); + if( nWideChar==0 ){ return 0; } - zMbcsText = sqlite3MallocZero( nByte*sizeof(WCHAR) ); + zMbcsText = sqlite3MallocZero( nWideChar*sizeof(WCHAR) ); if( zMbcsText==0 ){ return 0; } - nByte = osMultiByteToWideChar(codepage, 0, zText, -1, zMbcsText, - nByte); - if( nByte==0 ){ + nWideChar = osMultiByteToWideChar(codepage, 0, zText, -1, zMbcsText, + nWideChar); + if( nWideChar==0 ){ sqlite3_free(zMbcsText); zMbcsText = 0; } return zMbcsText; } +#ifdef _WIN32 /* ** Convert a Microsoft Unicode string to a multi-byte character string, ** using the ANSI or OEM code page. @@ -48646,6 +49019,7 @@ static char *winUnicodeToMbcs(LPCWSTR zWideText, int useAnsi){ } return zText; } +#endif /* _WIN32 */ /* ** Convert a multi-byte character string to UTF-8. @@ -48665,6 +49039,7 @@ static char *winMbcsToUtf8(const char *zText, int useAnsi){ return zTextUtf8; } +#ifdef _WIN32 /* ** Convert a UTF-8 string to a multi-byte character string. ** @@ -48714,6 +49089,7 @@ SQLITE_API char *sqlite3_win32_unicode_to_utf8(LPCWSTR zWideText){ #endif return winUnicodeToUtf8(zWideText); } +#endif /* _WIN32 */ /* ** This is a public wrapper for the winMbcsToUtf8() function. @@ -48731,6 +49107,7 @@ SQLITE_API char *sqlite3_win32_mbcs_to_utf8(const char *zText){ return winMbcsToUtf8(zText, osAreFileApisANSI()); } +#ifdef _WIN32 /* ** This is a public wrapper for the winMbcsToUtf8() function. */ @@ -48855,6 +49232,7 @@ SQLITE_API int sqlite3_win32_set_directory( ){ return sqlite3_win32_set_directory16(type, zValue); } +#endif /* _WIN32 */ /* ** The return value of winGetLastErrorMsg @@ -49403,13 +49781,94 @@ static BOOL winLockFile( ovlp.Offset = offsetLow; ovlp.OffsetHigh = offsetHigh; return osLockFileEx(*phFile, flags, 0, numBytesLow, numBytesHigh, &ovlp); +#ifdef SQLITE_WIN32_HAS_ANSI }else{ return osLockFile(*phFile, offsetLow, offsetHigh, numBytesLow, numBytesHigh); +#endif } #endif } +/* +** Lock a region of nByte bytes starting at offset offset of file hFile. +** Take an EXCLUSIVE lock if parameter bExclusive is true, or a SHARED lock +** otherwise. If nMs is greater than zero and the lock cannot be obtained +** immediately, block for that many ms before giving up. +** +** This function returns SQLITE_OK if the lock is obtained successfully. If +** some other process holds the lock, SQLITE_BUSY is returned if nMs==0, or +** SQLITE_BUSY_TIMEOUT otherwise. Or, if an error occurs, SQLITE_IOERR. +*/ +static int winHandleLockTimeout( + HANDLE hFile, + DWORD offset, + DWORD nByte, + int bExcl, + DWORD nMs +){ + DWORD flags = LOCKFILE_FAIL_IMMEDIATELY | (bExcl?LOCKFILE_EXCLUSIVE_LOCK:0); + int rc = SQLITE_OK; + BOOL ret; + + if( !osIsNT() ){ + ret = winLockFile(&hFile, flags, offset, 0, nByte, 0); + }else{ + OVERLAPPED ovlp; + memset(&ovlp, 0, sizeof(OVERLAPPED)); + ovlp.Offset = offset; + +#ifdef SQLITE_ENABLE_SETLK_TIMEOUT + if( nMs!=0 ){ + flags &= ~LOCKFILE_FAIL_IMMEDIATELY; + } + ovlp.hEvent = osCreateEvent(NULL, TRUE, FALSE, NULL); + if( ovlp.hEvent==NULL ){ + return SQLITE_IOERR_LOCK; + } +#endif + + ret = osLockFileEx(hFile, flags, 0, nByte, 0, &ovlp); + +#ifdef SQLITE_ENABLE_SETLK_TIMEOUT + /* If SQLITE_ENABLE_SETLK_TIMEOUT is defined, then the file-handle was + ** opened with FILE_FLAG_OVERHEAD specified. In this case, the call to + ** LockFileEx() may fail because the request is still pending. This can + ** happen even if LOCKFILE_FAIL_IMMEDIATELY was specified. + ** + ** If nMs is 0, then LOCKFILE_FAIL_IMMEDIATELY was set in the flags + ** passed to LockFileEx(). In this case, if the operation is pending, + ** block indefinitely until it is finished. + ** + ** Otherwise, wait for up to nMs ms for the operation to finish. nMs + ** may be set to INFINITE. + */ + if( !ret && GetLastError()==ERROR_IO_PENDING ){ + DWORD nDelay = (nMs==0 ? INFINITE : nMs); + DWORD res = osWaitForSingleObject(ovlp.hEvent, nDelay); + if( res==WAIT_OBJECT_0 ){ + ret = TRUE; + }else if( res==WAIT_TIMEOUT ){ + rc = SQLITE_BUSY_TIMEOUT; + }else{ + /* Some other error has occurred */ + rc = SQLITE_IOERR_LOCK; + } + + /* If it is still pending, cancel the LockFileEx() call. */ + osCancelIo(hFile); + } + + osCloseHandle(ovlp.hEvent); +#endif + } + + if( rc==SQLITE_OK && !ret ){ + rc = SQLITE_BUSY; + } + return rc; +} + /* ** Unlock a file region. */ @@ -49434,13 +49893,23 @@ static BOOL winUnlockFile( ovlp.Offset = offsetLow; ovlp.OffsetHigh = offsetHigh; return osUnlockFileEx(*phFile, 0, numBytesLow, numBytesHigh, &ovlp); +#ifdef SQLITE_WIN32_HAS_ANSI }else{ return osUnlockFile(*phFile, offsetLow, offsetHigh, numBytesLow, numBytesHigh); +#endif } #endif } +/* +** Remove an nByte lock starting at offset iOff from HANDLE h. +*/ +static int winHandleUnlock(HANDLE h, int iOff, int nByte){ + BOOL ret = winUnlockFile(&h, iOff, 0, nByte, 0); + return (ret ? SQLITE_OK : SQLITE_IOERR_UNLOCK); +} + /***************************************************************************** ** The next group of routines implement the I/O methods specified ** by the sqlite3_io_methods object. @@ -49454,66 +49923,70 @@ static BOOL winUnlockFile( #endif /* -** Move the current position of the file handle passed as the first -** argument to offset iOffset within the file. If successful, return 0. -** Otherwise, set pFile->lastErrno and return non-zero. +** Seek the file handle h to offset nByte of the file. +** +** If successful, return SQLITE_OK. Or, if an error occurs, return an SQLite +** error code. */ -static int winSeekFile(winFile *pFile, sqlite3_int64 iOffset){ +static int winHandleSeek(HANDLE h, sqlite3_int64 iOffset){ + int rc = SQLITE_OK; /* Return value */ + #if !SQLITE_OS_WINRT LONG upperBits; /* Most sig. 32 bits of new offset */ LONG lowerBits; /* Least sig. 32 bits of new offset */ DWORD dwRet; /* Value returned by SetFilePointer() */ - DWORD lastErrno; /* Value returned by GetLastError() */ - - OSTRACE(("SEEK file=%p, offset=%lld\n", pFile->h, iOffset)); upperBits = (LONG)((iOffset>>32) & 0x7fffffff); lowerBits = (LONG)(iOffset & 0xffffffff); + dwRet = osSetFilePointer(h, lowerBits, &upperBits, FILE_BEGIN); + /* API oddity: If successful, SetFilePointer() returns a dword ** containing the lower 32-bits of the new file-offset. Or, if it fails, ** it returns INVALID_SET_FILE_POINTER. However according to MSDN, ** INVALID_SET_FILE_POINTER may also be a valid new offset. So to determine ** whether an error has actually occurred, it is also necessary to call - ** GetLastError(). - */ - dwRet = osSetFilePointer(pFile->h, lowerBits, &upperBits, FILE_BEGIN); - - if( (dwRet==INVALID_SET_FILE_POINTER - && ((lastErrno = osGetLastError())!=NO_ERROR)) ){ - pFile->lastErrno = lastErrno; - winLogError(SQLITE_IOERR_SEEK, pFile->lastErrno, - "winSeekFile", pFile->zPath); - OSTRACE(("SEEK file=%p, rc=SQLITE_IOERR_SEEK\n", pFile->h)); - return 1; + ** GetLastError(). */ + if( dwRet==INVALID_SET_FILE_POINTER ){ + DWORD lastErrno = osGetLastError(); + if( lastErrno!=NO_ERROR ){ + rc = SQLITE_IOERR_SEEK; + } } - - OSTRACE(("SEEK file=%p, rc=SQLITE_OK\n", pFile->h)); - return 0; #else - /* - ** Same as above, except that this implementation works for WinRT. - */ - + /* This implementation works for WinRT. */ LARGE_INTEGER x; /* The new offset */ BOOL bRet; /* Value returned by SetFilePointerEx() */ x.QuadPart = iOffset; - bRet = osSetFilePointerEx(pFile->h, x, 0, FILE_BEGIN); + bRet = osSetFilePointerEx(h, x, 0, FILE_BEGIN); if(!bRet){ - pFile->lastErrno = osGetLastError(); - winLogError(SQLITE_IOERR_SEEK, pFile->lastErrno, - "winSeekFile", pFile->zPath); - OSTRACE(("SEEK file=%p, rc=SQLITE_IOERR_SEEK\n", pFile->h)); - return 1; + rc = SQLITE_IOERR_SEEK; } - - OSTRACE(("SEEK file=%p, rc=SQLITE_OK\n", pFile->h)); - return 0; #endif + + OSTRACE(("SEEK file=%p, offset=%lld rc=%s\n", h, iOffset, sqlite3ErrName(rc))); + return rc; +} + +/* +** Move the current position of the file handle passed as the first +** argument to offset iOffset within the file. If successful, return 0. +** Otherwise, set pFile->lastErrno and return non-zero. +*/ +static int winSeekFile(winFile *pFile, sqlite3_int64 iOffset){ + int rc; + + rc = winHandleSeek(pFile->h, iOffset); + if( rc!=SQLITE_OK ){ + pFile->lastErrno = osGetLastError(); + winLogError(rc, pFile->lastErrno, "winSeekFile", pFile->zPath); + } + return rc; } + #if SQLITE_MAX_MMAP_SIZE>0 /* Forward references to VFS helper methods used for memory mapped files */ static int winMapfile(winFile*, sqlite3_int64); @@ -49773,6 +50246,60 @@ static int winWrite( return SQLITE_OK; } +/* +** Truncate the file opened by handle h to nByte bytes in size. +*/ +static int winHandleTruncate(HANDLE h, sqlite3_int64 nByte){ + int rc = SQLITE_OK; /* Return code */ + rc = winHandleSeek(h, nByte); + if( rc==SQLITE_OK ){ + if( 0==osSetEndOfFile(h) ){ + rc = SQLITE_IOERR_TRUNCATE; + } + } + return rc; +} + +/* +** Determine the size in bytes of the file opened by the handle passed as +** the first argument. +*/ +static int winHandleSize(HANDLE h, sqlite3_int64 *pnByte){ + int rc = SQLITE_OK; + +#if SQLITE_OS_WINRT + FILE_STANDARD_INFO info; + BOOL b; + b = osGetFileInformationByHandleEx(h, FileStandardInfo, &info, sizeof(info)); + if( b ){ + *pnByte = info.EndOfFile.QuadPart; + }else{ + rc = SQLITE_IOERR_FSTAT; + } +#else + DWORD upperBits = 0; + DWORD lowerBits = 0; + + assert( pnByte ); + lowerBits = osGetFileSize(h, &upperBits); + *pnByte = (((sqlite3_int64)upperBits)<<32) + lowerBits; + if( lowerBits==INVALID_FILE_SIZE && osGetLastError()!=NO_ERROR ){ + rc = SQLITE_IOERR_FSTAT; + } +#endif + + return rc; +} + +/* +** Close the handle passed as the only argument. +*/ +static void winHandleClose(HANDLE h){ + if( h!=INVALID_HANDLE_VALUE ){ + osCloseHandle(h); + } +} + /* ** Truncate an open file to a specified size */ @@ -50028,8 +50555,9 @@ static int winFileSize(sqlite3_file *id, sqlite3_int64 *pSize){ ** Different API routines are called depending on whether or not this ** is Win9x or WinNT. */ -static int winGetReadLock(winFile *pFile){ +static int winGetReadLock(winFile *pFile, int bBlock){ int res; + DWORD mask = ~(bBlock ? LOCKFILE_FAIL_IMMEDIATELY : 0); OSTRACE(("READ-LOCK file=%p, lock=%d\n", pFile->h, pFile->locktype)); if( osIsNT() ){ #if SQLITE_OS_WINCE @@ -50039,7 +50567,7 @@ static int winGetReadLock(winFile *pFile){ */ res = winceLockFile(&pFile->h, SHARED_FIRST, 0, 1, 0); #else - res = winLockFile(&pFile->h, SQLITE_LOCKFILEEX_FLAGS, SHARED_FIRST, 0, + res = winLockFile(&pFile->h, SQLITE_LOCKFILEEX_FLAGS&mask, SHARED_FIRST, 0, SHARED_SIZE, 0); #endif } @@ -50048,7 +50576,7 @@ static int winGetReadLock(winFile *pFile){ int lk; sqlite3_randomness(sizeof(lk), &lk); pFile->sharedLockByte = (short)((lk & 0x7fffffff)%(SHARED_SIZE - 1)); - res = winLockFile(&pFile->h, SQLITE_LOCKFILE_FLAGS, + res = winLockFile(&pFile->h, SQLITE_LOCKFILE_FLAGS&mask, SHARED_FIRST+pFile->sharedLockByte, 0, 1, 0); } #endif @@ -50143,46 +50671,62 @@ static int winLock(sqlite3_file *id, int locktype){ assert( locktype!=PENDING_LOCK ); assert( locktype!=RESERVED_LOCK || pFile->locktype==SHARED_LOCK ); - /* Lock the PENDING_LOCK byte if we need to acquire a PENDING lock or + /* Lock the PENDING_LOCK byte if we need to acquire an EXCLUSIVE lock or ** a SHARED lock. If we are acquiring a SHARED lock, the acquisition of ** the PENDING_LOCK byte is temporary. */ newLocktype = pFile->locktype; - if( pFile->locktype==NO_LOCK - || (locktype==EXCLUSIVE_LOCK && pFile->locktype<=RESERVED_LOCK) + if( locktype==SHARED_LOCK + || (locktype==EXCLUSIVE_LOCK && pFile->locktype==RESERVED_LOCK) ){ int cnt = 3; - while( cnt-->0 && (res = winLockFile(&pFile->h, SQLITE_LOCKFILE_FLAGS, - PENDING_BYTE, 0, 1, 0))==0 ){ + + /* Flags for the LockFileEx() call. This should be an exclusive lock if + ** this call is to obtain EXCLUSIVE, or a shared lock if this call is to + ** obtain SHARED. */ + int flags = LOCKFILE_FAIL_IMMEDIATELY; + if( locktype==EXCLUSIVE_LOCK ){ + flags |= LOCKFILE_EXCLUSIVE_LOCK; + } + while( cnt>0 ){ /* Try 3 times to get the pending lock. This is needed to work ** around problems caused by indexing and/or anti-virus software on ** Windows systems. + ** ** If you are using this code as a model for alternative VFSes, do not - ** copy this retry logic. It is a hack intended for Windows only. - */ + ** copy this retry logic. It is a hack intended for Windows only. */ + res = winLockFile(&pFile->h, flags, PENDING_BYTE, 0, 1, 0); + if( res ) break; + lastErrno = osGetLastError(); OSTRACE(("LOCK-PENDING-FAIL file=%p, count=%d, result=%d\n", - pFile->h, cnt, res)); + pFile->h, cnt, res + )); + if( lastErrno==ERROR_INVALID_HANDLE ){ pFile->lastErrno = lastErrno; rc = SQLITE_IOERR_LOCK; OSTRACE(("LOCK-FAIL file=%p, count=%d, rc=%s\n", - pFile->h, cnt, sqlite3ErrName(rc))); + pFile->h, cnt, sqlite3ErrName(rc) + )); return rc; } - if( cnt ) sqlite3_win32_sleep(1); + + cnt--; + if( cnt>0 ) sqlite3_win32_sleep(1); } gotPendingLock = res; - if( !res ){ - lastErrno = osGetLastError(); - } } /* Acquire a shared lock */ if( locktype==SHARED_LOCK && res ){ assert( pFile->locktype==NO_LOCK ); - res = winGetReadLock(pFile); +#ifdef SQLITE_ENABLE_SETLK_TIMEOUT + res = winGetReadLock(pFile, pFile->bBlockOnConnect); +#else + res = winGetReadLock(pFile, 0); +#endif if( res ){ newLocktype = SHARED_LOCK; }else{ @@ -50220,7 +50764,7 @@ static int winLock(sqlite3_file *id, int locktype){ newLocktype = EXCLUSIVE_LOCK; }else{ lastErrno = osGetLastError(); - winGetReadLock(pFile); + winGetReadLock(pFile, 0); } } @@ -50300,7 +50844,7 @@ static int winUnlock(sqlite3_file *id, int locktype){ type = pFile->locktype; if( type>=EXCLUSIVE_LOCK ){ winUnlockFile(&pFile->h, SHARED_FIRST, 0, SHARED_SIZE, 0); - if( locktype==SHARED_LOCK && !winGetReadLock(pFile) ){ + if( locktype==SHARED_LOCK && !winGetReadLock(pFile, 0) ){ /* This should never happen. We should always be able to ** reacquire the read lock */ rc = winLogError(SQLITE_IOERR_UNLOCK, osGetLastError(), @@ -50510,6 +51054,28 @@ static int winFileControl(sqlite3_file *id, int op, void *pArg){ return rc; } #endif + +#ifdef SQLITE_ENABLE_SETLK_TIMEOUT + case SQLITE_FCNTL_LOCK_TIMEOUT: { + int iOld = pFile->iBusyTimeout; + int iNew = *(int*)pArg; +#if SQLITE_ENABLE_SETLK_TIMEOUT==1 + pFile->iBusyTimeout = (iNew < 0) ? INFINITE : (DWORD)iNew; +#elif SQLITE_ENABLE_SETLK_TIMEOUT==2 + pFile->iBusyTimeout = (DWORD)(!!iNew); +#else +# error "SQLITE_ENABLE_SETLK_TIMEOUT must be set to 1 or 2" +#endif + *(int*)pArg = iOld; + return SQLITE_OK; + } + case SQLITE_FCNTL_BLOCK_ON_CONNECT: { + int iNew = *(int*)pArg; + pFile->bBlockOnConnect = iNew; + return SQLITE_OK; + } +#endif /* SQLITE_ENABLE_SETLK_TIMEOUT */ + } OSTRACE(("FCNTL file=%p, rc=SQLITE_NOTFOUND\n", pFile->h)); return SQLITE_NOTFOUND; @@ -50590,23 +51156,27 @@ static int winShmMutexHeld(void) { ** ** The following fields are read-only after the object is created: ** -** fid ** zFilename ** ** Either winShmNode.mutex must be held or winShmNode.nRef==0 and ** winShmMutexHeld() is true when reading or writing any other field ** in this structure. ** +** File-handle hSharedShm is used to (a) take the DMS lock, (b) truncate +** the *-shm file if the DMS-locking protocol demands it, and (c) map +** regions of the *-shm file into memory using MapViewOfFile() or +** similar. Other locks are taken by individual clients using the +** winShm.hShm handles. */ struct winShmNode { sqlite3_mutex *mutex; /* Mutex to access this object */ char *zFilename; /* Name of the file */ - winFile hFile; /* File handle from winOpen */ + HANDLE hSharedShm; /* File handle open on zFilename */ + int isUnlocked; /* DMS lock has not yet been obtained */ + int isReadonly; /* True if read-only */ int szRegion; /* Size of shared-memory regions */ int nRegion; /* Size of array apRegion */ - u8 isReadonly; /* True if read-only */ - u8 isUnlocked; /* True if no DMS lock held */ struct ShmRegion { HANDLE hMap; /* File handle from CreateFileMapping */ @@ -50615,7 +51185,6 @@ struct winShmNode { DWORD lastErrno; /* The Windows errno from the last I/O error */ int nRef; /* Number of winShm objects pointing to this */ - winShm *pFirst; /* All winShm objects pointing to this */ winShmNode *pNext; /* Next in list of all winShmNode objects */ #if defined(SQLITE_DEBUG) || defined(SQLITE_HAVE_OS_TRACE) u8 nextShmId; /* Next available winShm.id value */ @@ -50631,23 +51200,15 @@ static winShmNode *winShmNodeList = 0; /* ** Structure used internally by this VFS to record the state of an -** open shared memory connection. -** -** The following fields are initialized when this object is created and -** are read-only thereafter: -** -** winShm.pShmNode -** winShm.id -** -** All other fields are read/write. The winShm.pShmNode->mutex must be held -** while accessing any read/write fields. +** open shared memory connection. There is one such structure for each +** winFile open on a wal mode database. */ struct winShm { winShmNode *pShmNode; /* The underlying winShmNode object */ - winShm *pNext; /* Next winShm with the same winShmNode */ - u8 hasMutex; /* True if holding the winShmNode mutex */ u16 sharedMask; /* Mask of shared locks held */ u16 exclMask; /* Mask of exclusive locks held */ + HANDLE hShm; /* File-handle on *-shm file. For locking. */ + int bReadonly; /* True if hShm is opened read-only */ #if defined(SQLITE_DEBUG) || defined(SQLITE_HAVE_OS_TRACE) u8 id; /* Id of this connection with its winShmNode */ #endif @@ -50659,50 +51220,6 @@ struct winShm { #define WIN_SHM_BASE ((22+SQLITE_SHM_NLOCK)*4) /* first lock byte */ #define WIN_SHM_DMS (WIN_SHM_BASE+SQLITE_SHM_NLOCK) /* deadman switch */ -/* -** Apply advisory locks for all n bytes beginning at ofst. -*/ -#define WINSHM_UNLCK 1 -#define WINSHM_RDLCK 2 -#define WINSHM_WRLCK 3 -static int winShmSystemLock( - winShmNode *pFile, /* Apply locks to this open shared-memory segment */ - int lockType, /* WINSHM_UNLCK, WINSHM_RDLCK, or WINSHM_WRLCK */ - int ofst, /* Offset to first byte to be locked/unlocked */ - int nByte /* Number of bytes to lock or unlock */ -){ - int rc = 0; /* Result code form Lock/UnlockFileEx() */ - - /* Access to the winShmNode object is serialized by the caller */ - assert( pFile->nRef==0 || sqlite3_mutex_held(pFile->mutex) ); - - OSTRACE(("SHM-LOCK file=%p, lock=%d, offset=%d, size=%d\n", - pFile->hFile.h, lockType, ofst, nByte)); - - /* Release/Acquire the system-level lock */ - if( lockType==WINSHM_UNLCK ){ - rc = winUnlockFile(&pFile->hFile.h, ofst, 0, nByte, 0); - }else{ - /* Initialize the locking parameters */ - DWORD dwFlags = LOCKFILE_FAIL_IMMEDIATELY; - if( lockType == WINSHM_WRLCK ) dwFlags |= LOCKFILE_EXCLUSIVE_LOCK; - rc = winLockFile(&pFile->hFile.h, dwFlags, ofst, 0, nByte, 0); - } - - if( rc!= 0 ){ - rc = SQLITE_OK; - }else{ - pFile->lastErrno = osGetLastError(); - rc = SQLITE_BUSY; - } - - OSTRACE(("SHM-LOCK file=%p, func=%s, errno=%lu, rc=%s\n", - pFile->hFile.h, (lockType == WINSHM_UNLCK) ? "winUnlockFile" : - "winLockFile", pFile->lastErrno, sqlite3ErrName(rc))); - - return rc; -} - /* Forward references to VFS methods */ static int winOpen(sqlite3_vfs*,const char*,sqlite3_file*,int,int*); static int winDelete(sqlite3_vfs *,const char*,int); @@ -50734,11 +51251,7 @@ static void winShmPurge(sqlite3_vfs *pVfs, int deleteFlag){ osGetCurrentProcessId(), i, bRc ? "ok" : "failed")); UNUSED_VARIABLE_VALUE(bRc); } - if( p->hFile.h!=NULL && p->hFile.h!=INVALID_HANDLE_VALUE ){ - SimulateIOErrorBenign(1); - winClose((sqlite3_file *)&p->hFile); - SimulateIOErrorBenign(0); - } + winHandleClose(p->hSharedShm); if( deleteFlag ){ SimulateIOErrorBenign(1); sqlite3BeginBenignMalloc(); @@ -50756,42 +51269,239 @@ static void winShmPurge(sqlite3_vfs *pVfs, int deleteFlag){ } /* -** The DMS lock has not yet been taken on shm file pShmNode. Attempt to -** take it now. Return SQLITE_OK if successful, or an SQLite error -** code otherwise. -** -** If the DMS cannot be locked because this is a readonly_shm=1 -** connection and no other process already holds a lock, return -** SQLITE_READONLY_CANTINIT and set pShmNode->isUnlocked=1. +** The DMS lock has not yet been taken on the shm file associated with +** pShmNode. Take the lock. Truncate the *-shm file if required. +** Return SQLITE_OK if successful, or an SQLite error code otherwise. */ -static int winLockSharedMemory(winShmNode *pShmNode){ - int rc = winShmSystemLock(pShmNode, WINSHM_WRLCK, WIN_SHM_DMS, 1); +static int winLockSharedMemory(winShmNode *pShmNode, DWORD nMs){ + HANDLE h = pShmNode->hSharedShm; + int rc = SQLITE_OK; + assert( sqlite3_mutex_held(pShmNode->mutex) ); + rc = winHandleLockTimeout(h, WIN_SHM_DMS, 1, 1, 0); if( rc==SQLITE_OK ){ + /* We have an EXCLUSIVE lock on the DMS byte. This means that this + ** is the first process to open the file. Truncate it to zero bytes + ** in this case. */ if( pShmNode->isReadonly ){ - pShmNode->isUnlocked = 1; - winShmSystemLock(pShmNode, WINSHM_UNLCK, WIN_SHM_DMS, 1); - return SQLITE_READONLY_CANTINIT; - }else if( winTruncate((sqlite3_file*)&pShmNode->hFile, 0) ){ - winShmSystemLock(pShmNode, WINSHM_UNLCK, WIN_SHM_DMS, 1); - return winLogError(SQLITE_IOERR_SHMOPEN, osGetLastError(), - "winLockSharedMemory", pShmNode->zFilename); + rc = SQLITE_READONLY_CANTINIT; + }else{ + rc = winHandleTruncate(h, 0); } + + /* Release the EXCLUSIVE lock acquired above. */ + winUnlockFile(&h, WIN_SHM_DMS, 0, 1, 0); + }else if( (rc & 0xFF)==SQLITE_BUSY ){ + rc = SQLITE_OK; } if( rc==SQLITE_OK ){ - winShmSystemLock(pShmNode, WINSHM_UNLCK, WIN_SHM_DMS, 1); + /* Take a SHARED lock on the DMS byte. */ + rc = winHandleLockTimeout(h, WIN_SHM_DMS, 1, 0, nMs); + if( rc==SQLITE_OK ){ + pShmNode->isUnlocked = 0; + } } - return winShmSystemLock(pShmNode, WINSHM_RDLCK, WIN_SHM_DMS, 1); + return rc; } + /* -** Open the shared-memory area associated with database file pDbFd. +** Convert a UTF-8 filename into whatever form the underlying +** operating system wants filenames in. Space to hold the result +** is obtained from malloc and must be freed by the calling +** function +** +** On Cygwin, 3 possible input forms are accepted: +** - If the filename starts with ":/" or ":\", +** it is converted to UTF-16 as-is. +** - If the filename contains '/', it is assumed to be a +** Cygwin absolute path, it is converted to a win32 +** absolute path in UTF-16. +** - Otherwise it must be a filename only, the win32 filename +** is returned in UTF-16. +** Note: If the function cygwin_conv_path() fails, only +** UTF-8 -> UTF-16 conversion will be done. This can only +** happen when the file path >32k, in which case winUtf8ToUnicode() +** will fail too. +*/ +static void *winConvertFromUtf8Filename(const char *zFilename){ + void *zConverted = 0; + if( osIsNT() ){ +#ifdef __CYGWIN__ + int nChar; + LPWSTR zWideFilename; + + if( osCygwin_conv_path && !(winIsDriveLetterAndColon(zFilename) + && winIsDirSep(zFilename[2])) ){ + i64 nByte; + int convertflag = CCP_POSIX_TO_WIN_W; + if( !strchr(zFilename, '/') ) convertflag |= CCP_RELATIVE; + nByte = (i64)osCygwin_conv_path(convertflag, + zFilename, 0, 0); + if( nByte>0 ){ + zConverted = sqlite3MallocZero(12+(u64)nByte); + if ( zConverted==0 ){ + return zConverted; + } + zWideFilename = zConverted; + /* Filenames should be prefixed, except when converted + * full path already starts with "\\?\". */ + if( osCygwin_conv_path(convertflag, zFilename, + zWideFilename+4, nByte)==0 ){ + if( (convertflag&CCP_RELATIVE) ){ + memmove(zWideFilename, zWideFilename+4, nByte); + }else if( memcmp(zWideFilename+4, L"\\\\", 4) ){ + memcpy(zWideFilename, L"\\\\?\\", 8); + }else if( zWideFilename[6]!='?' ){ + memmove(zWideFilename+6, zWideFilename+4, nByte); + memcpy(zWideFilename, L"\\\\?\\UNC", 14); + }else{ + memmove(zWideFilename, zWideFilename+4, nByte); + } + return zConverted; + } + sqlite3_free(zConverted); + } + } + nChar = osMultiByteToWideChar(CP_UTF8, 0, zFilename, -1, NULL, 0); + if( nChar==0 ){ + return 0; + } + zWideFilename = sqlite3MallocZero( nChar*sizeof(WCHAR)+12 ); + if( zWideFilename==0 ){ + return 0; + } + nChar = osMultiByteToWideChar(CP_UTF8, 0, zFilename, -1, + zWideFilename, nChar); + if( nChar==0 ){ + sqlite3_free(zWideFilename); + zWideFilename = 0; + }else if( nChar>MAX_PATH + && winIsDriveLetterAndColon(zFilename) + && winIsDirSep(zFilename[2]) ){ + memmove(zWideFilename+4, zWideFilename, nChar*sizeof(WCHAR)); + zWideFilename[2] = '\\'; + memcpy(zWideFilename, L"\\\\?\\", 8); + }else if( nChar>MAX_PATH + && winIsDirSep(zFilename[0]) && winIsDirSep(zFilename[1]) + && zFilename[2] != '?' ){ + memmove(zWideFilename+6, zWideFilename, nChar*sizeof(WCHAR)); + memcpy(zWideFilename, L"\\\\?\\UNC", 14); + } + zConverted = zWideFilename; +#else + zConverted = winUtf8ToUnicode(zFilename); +#endif /* __CYGWIN__ */ + } +#if defined(SQLITE_WIN32_HAS_ANSI) && defined(_WIN32) + else{ + zConverted = winUtf8ToMbcs(zFilename, osAreFileApisANSI()); + } +#endif + /* caller will handle out of memory */ + return zConverted; +} + +/* +** This function is used to open a handle on a *-shm file. ** -** When opening a new shared-memory file, if no other instances of that -** file are currently open, in this process or in other processes, then -** the file must be truncated to zero length or have its header cleared. +** If SQLITE_ENABLE_SETLK_TIMEOUT is defined at build time, then the file +** is opened with FILE_FLAG_OVERLAPPED specified. If not, it is not. +*/ +static int winHandleOpen( + const char *zUtf8, /* File to open */ + int *pbReadonly, /* IN/OUT: True for readonly handle */ + HANDLE *ph /* OUT: New HANDLE for file */ +){ + int rc = SQLITE_OK; + void *zConverted = 0; + int bReadonly = *pbReadonly; + HANDLE h = INVALID_HANDLE_VALUE; + +#ifdef SQLITE_ENABLE_SETLK_TIMEOUT + const DWORD flag_overlapped = FILE_FLAG_OVERLAPPED; +#else + const DWORD flag_overlapped = 0; +#endif + + /* Convert the filename to the system encoding. */ + zConverted = winConvertFromUtf8Filename(zUtf8); + if( zConverted==0 ){ + OSTRACE(("OPEN name=%s, rc=SQLITE_IOERR_NOMEM", zUtf8)); + rc = SQLITE_IOERR_NOMEM_BKPT; + goto winopenfile_out; + } + + /* Ensure the file we are trying to open is not actually a directory. */ + if( winIsDir(zConverted) ){ + OSTRACE(("OPEN name=%s, rc=SQLITE_CANTOPEN_ISDIR", zUtf8)); + rc = SQLITE_CANTOPEN_ISDIR; + goto winopenfile_out; + } + + /* TODO: platforms. + ** TODO: retry-on-ioerr. + */ + if( osIsNT() ){ +#if SQLITE_OS_WINRT + CREATEFILE2_EXTENDED_PARAMETERS extendedParameters; + memset(&extendedParameters, 0, sizeof(extendedParameters)); + extendedParameters.dwSize = sizeof(extendedParameters); + extendedParameters.dwFileAttributes = FILE_ATTRIBUTE_NORMAL; + extendedParameters.dwFileFlags = flag_overlapped; + extendedParameters.dwSecurityQosFlags = SECURITY_ANONYMOUS; + h = osCreateFile2((LPCWSTR)zConverted, + (GENERIC_READ | (bReadonly ? 0 : GENERIC_WRITE)),/* dwDesiredAccess */ + FILE_SHARE_READ | FILE_SHARE_WRITE, /* dwShareMode */ + OPEN_ALWAYS, /* dwCreationDisposition */ + &extendedParameters + ); +#else + h = osCreateFileW((LPCWSTR)zConverted, /* lpFileName */ + (GENERIC_READ | (bReadonly ? 0 : GENERIC_WRITE)), /* dwDesiredAccess */ + FILE_SHARE_READ | FILE_SHARE_WRITE, /* dwShareMode */ + NULL, /* lpSecurityAttributes */ + OPEN_ALWAYS, /* dwCreationDisposition */ + FILE_ATTRIBUTE_NORMAL|flag_overlapped, + NULL + ); +#endif + }else{ + /* Due to pre-processor directives earlier in this file, + ** SQLITE_WIN32_HAS_ANSI is always defined if osIsNT() is false. */ +#ifdef SQLITE_WIN32_HAS_ANSI + h = osCreateFileA((LPCSTR)zConverted, + (GENERIC_READ | (bReadonly ? 0 : GENERIC_WRITE)), /* dwDesiredAccess */ + FILE_SHARE_READ | FILE_SHARE_WRITE, /* dwShareMode */ + NULL, /* lpSecurityAttributes */ + OPEN_ALWAYS, /* dwCreationDisposition */ + FILE_ATTRIBUTE_NORMAL|flag_overlapped, + NULL + ); +#endif + } + + if( h==INVALID_HANDLE_VALUE ){ + if( bReadonly==0 ){ + bReadonly = 1; + rc = winHandleOpen(zUtf8, &bReadonly, &h); + }else{ + rc = SQLITE_CANTOPEN_BKPT; + } + } + + winopenfile_out: + sqlite3_free(zConverted); + *pbReadonly = bReadonly; + *ph = h; + return rc; +} + + +/* +** Open the shared-memory area associated with database file pDbFd. */ static int winOpenSharedMemory(winFile *pDbFd){ struct winShm *p; /* The connection to be opened */ @@ -50803,98 +51513,83 @@ static int winOpenSharedMemory(winFile *pDbFd){ assert( pDbFd->pShm==0 ); /* Not previously opened */ /* Allocate space for the new sqlite3_shm object. Also speculatively - ** allocate space for a new winShmNode and filename. - */ + ** allocate space for a new winShmNode and filename. */ p = sqlite3MallocZero( sizeof(*p) ); if( p==0 ) return SQLITE_IOERR_NOMEM_BKPT; nName = sqlite3Strlen30(pDbFd->zPath); - pNew = sqlite3MallocZero( sizeof(*pShmNode) + nName + 17 ); + pNew = sqlite3MallocZero( sizeof(*pShmNode) + (i64)nName + 17 ); if( pNew==0 ){ sqlite3_free(p); return SQLITE_IOERR_NOMEM_BKPT; } pNew->zFilename = (char*)&pNew[1]; + pNew->hSharedShm = INVALID_HANDLE_VALUE; + pNew->isUnlocked = 1; sqlite3_snprintf(nName+15, pNew->zFilename, "%s-shm", pDbFd->zPath); sqlite3FileSuffix3(pDbFd->zPath, pNew->zFilename); + /* Open a file-handle on the *-shm file for this connection. This file-handle + ** is only used for locking. The mapping of the *-shm file is created using + ** the shared file handle in winShmNode.hSharedShm. */ + p->bReadonly = sqlite3_uri_boolean(pDbFd->zPath, "readonly_shm", 0); + rc = winHandleOpen(pNew->zFilename, &p->bReadonly, &p->hShm); + /* Look to see if there is an existing winShmNode that can be used. - ** If no matching winShmNode currently exists, create a new one. - */ + ** If no matching winShmNode currently exists, then create a new one. */ winShmEnterMutex(); for(pShmNode = winShmNodeList; pShmNode; pShmNode=pShmNode->pNext){ /* TBD need to come up with better match here. Perhaps - ** use FILE_ID_BOTH_DIR_INFO Structure. - */ + ** use FILE_ID_BOTH_DIR_INFO Structure. */ if( sqlite3StrICmp(pShmNode->zFilename, pNew->zFilename)==0 ) break; } - if( pShmNode ){ - sqlite3_free(pNew); - }else{ - int inFlags = SQLITE_OPEN_WAL; - int outFlags = 0; - + if( pShmNode==0 ){ pShmNode = pNew; - pNew = 0; - ((winFile*)(&pShmNode->hFile))->h = INVALID_HANDLE_VALUE; - pShmNode->pNext = winShmNodeList; - winShmNodeList = pShmNode; + /* Allocate a mutex for this winShmNode object, if one is required. */ if( sqlite3GlobalConfig.bCoreMutex ){ pShmNode->mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST); - if( pShmNode->mutex==0 ){ - rc = SQLITE_IOERR_NOMEM_BKPT; - goto shm_open_err; - } + if( pShmNode->mutex==0 ) rc = SQLITE_IOERR_NOMEM_BKPT; } - if( 0==sqlite3_uri_boolean(pDbFd->zPath, "readonly_shm", 0) ){ - inFlags |= SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE; - }else{ - inFlags |= SQLITE_OPEN_READONLY; - } - rc = winOpen(pDbFd->pVfs, pShmNode->zFilename, - (sqlite3_file*)&pShmNode->hFile, - inFlags, &outFlags); - if( rc!=SQLITE_OK ){ - rc = winLogError(rc, osGetLastError(), "winOpenShm", - pShmNode->zFilename); - goto shm_open_err; + /* Open a file-handle to use for mappings, and for the DMS lock. */ + if( rc==SQLITE_OK ){ + HANDLE h = INVALID_HANDLE_VALUE; + pShmNode->isReadonly = p->bReadonly; + rc = winHandleOpen(pNew->zFilename, &pShmNode->isReadonly, &h); + pShmNode->hSharedShm = h; } - if( outFlags==SQLITE_OPEN_READONLY ) pShmNode->isReadonly = 1; - rc = winLockSharedMemory(pShmNode); - if( rc!=SQLITE_OK && rc!=SQLITE_READONLY_CANTINIT ) goto shm_open_err; + /* If successful, link the new winShmNode into the global list. If an + ** error occurred, free the object. */ + if( rc==SQLITE_OK ){ + pShmNode->pNext = winShmNodeList; + winShmNodeList = pShmNode; + pNew = 0; + }else{ + sqlite3_mutex_free(pShmNode->mutex); + if( pShmNode->hSharedShm!=INVALID_HANDLE_VALUE ){ + osCloseHandle(pShmNode->hSharedShm); + } + } } - /* Make the new connection a child of the winShmNode */ - p->pShmNode = pShmNode; + /* If no error has occurred, link the winShm object to the winShmNode and + ** the winShm to pDbFd. */ + if( rc==SQLITE_OK ){ + p->pShmNode = pShmNode; + pShmNode->nRef++; #if defined(SQLITE_DEBUG) || defined(SQLITE_HAVE_OS_TRACE) - p->id = pShmNode->nextShmId++; + p->id = pShmNode->nextShmId++; #endif - pShmNode->nRef++; - pDbFd->pShm = p; - winShmLeaveMutex(); - - /* The reference count on pShmNode has already been incremented under - ** the cover of the winShmEnterMutex() mutex and the pointer from the - ** new (struct winShm) object to the pShmNode has been set. All that is - ** left to do is to link the new object into the linked list starting - ** at pShmNode->pFirst. This must be done while holding the pShmNode->mutex - ** mutex. - */ - sqlite3_mutex_enter(pShmNode->mutex); - p->pNext = pShmNode->pFirst; - pShmNode->pFirst = p; - sqlite3_mutex_leave(pShmNode->mutex); - return rc; + pDbFd->pShm = p; + }else if( p ){ + winHandleClose(p->hShm); + sqlite3_free(p); + } - /* Jump here on any error */ -shm_open_err: - winShmSystemLock(pShmNode, WINSHM_UNLCK, WIN_SHM_DMS, 1); - winShmPurge(pDbFd->pVfs, 0); /* This call frees pShmNode if required */ - sqlite3_free(p); - sqlite3_free(pNew); + assert( rc!=SQLITE_OK || pShmNode->isUnlocked==0 || pShmNode->nRegion==0 ); winShmLeaveMutex(); + sqlite3_free(pNew); return rc; } @@ -50909,27 +51604,19 @@ static int winShmUnmap( winFile *pDbFd; /* Database holding shared-memory */ winShm *p; /* The connection to be closed */ winShmNode *pShmNode; /* The underlying shared-memory file */ - winShm **pp; /* For looping over sibling connections */ pDbFd = (winFile*)fd; p = pDbFd->pShm; if( p==0 ) return SQLITE_OK; - pShmNode = p->pShmNode; - - /* Remove connection p from the set of connections associated - ** with pShmNode */ - sqlite3_mutex_enter(pShmNode->mutex); - for(pp=&pShmNode->pFirst; (*pp)!=p; pp = &(*pp)->pNext){} - *pp = p->pNext; + if( p->hShm!=INVALID_HANDLE_VALUE ){ + osCloseHandle(p->hShm); + } - /* Free the connection p */ - sqlite3_free(p); - pDbFd->pShm = 0; - sqlite3_mutex_leave(pShmNode->mutex); + pShmNode = p->pShmNode; + winShmEnterMutex(); /* If pShmNode->nRef has reached 0, then close the underlying - ** shared-memory file, too */ - winShmEnterMutex(); + ** shared-memory file, too. */ assert( pShmNode->nRef>0 ); pShmNode->nRef--; if( pShmNode->nRef==0 ){ @@ -50937,6 +51624,9 @@ static int winShmUnmap( } winShmLeaveMutex(); + /* Free the connection p */ + sqlite3_free(p); + pDbFd->pShm = 0; return SQLITE_OK; } @@ -50951,10 +51641,9 @@ static int winShmLock( ){ winFile *pDbFd = (winFile*)fd; /* Connection holding shared memory */ winShm *p = pDbFd->pShm; /* The shared memory being locked */ - winShm *pX; /* For looping over all siblings */ winShmNode *pShmNode; int rc = SQLITE_OK; /* Result code */ - u16 mask; /* Mask of locks to take or release */ + u16 mask = (u16)((1U<<(ofst+n)) - (1U<pShmNode; @@ -50968,85 +51657,82 @@ static int winShmLock( || flags==(SQLITE_SHM_UNLOCK | SQLITE_SHM_EXCLUSIVE) ); assert( n==1 || (flags & SQLITE_SHM_EXCLUSIVE)!=0 ); - mask = (u16)((1U<<(ofst+n)) - (1U<1 || mask==(1<mutex); - if( flags & SQLITE_SHM_UNLOCK ){ - u16 allMask = 0; /* Mask of locks held by siblings */ - - /* See if any siblings hold this same lock */ - for(pX=pShmNode->pFirst; pX; pX=pX->pNext){ - if( pX==p ) continue; - assert( (pX->exclMask & (p->exclMask|p->sharedMask))==0 ); - allMask |= pX->sharedMask; - } + /* Check that, if this to be a blocking lock, no locks that occur later + ** in the following list than the lock being obtained are already held: + ** + ** 1. Checkpointer lock (ofst==1). + ** 2. Write lock (ofst==0). + ** 3. Read locks (ofst>=3 && ofstexclMask|p->sharedMask); + assert( (flags & SQLITE_SHM_UNLOCK) || pDbFd->iBusyTimeout==0 || ( + (ofst!=2) /* not RECOVER */ + && (ofst!=1 || lockMask==0 || lockMask==2) + && (ofst!=0 || lockMask<3) + && (ofst<3 || lockMask<(1<exclMask & mask) + ); + if( ((flags & SQLITE_SHM_UNLOCK) && ((p->exclMask|p->sharedMask) & mask)) + || (flags==(SQLITE_SHM_SHARED|SQLITE_SHM_LOCK) && 0==(p->sharedMask & mask)) + || (flags==(SQLITE_SHM_EXCLUSIVE|SQLITE_SHM_LOCK)) + ){ - /* Undo the local locks */ - if( rc==SQLITE_OK ){ - p->exclMask &= ~mask; - p->sharedMask &= ~mask; - } - }else if( flags & SQLITE_SHM_SHARED ){ - u16 allShared = 0; /* Union of locks held by connections other than "p" */ + if( flags & SQLITE_SHM_UNLOCK ){ + /* Case (a) - unlock. */ - /* Find out which shared locks are already held by sibling connections. - ** If any sibling already holds an exclusive lock, go ahead and return - ** SQLITE_BUSY. - */ - for(pX=pShmNode->pFirst; pX; pX=pX->pNext){ - if( (pX->exclMask & mask)!=0 ){ - rc = SQLITE_BUSY; - break; - } - allShared |= pX->sharedMask; - } + assert( (p->exclMask & p->sharedMask)==0 ); + assert( !(flags & SQLITE_SHM_EXCLUSIVE) || (p->exclMask & mask)==mask ); + assert( !(flags & SQLITE_SHM_SHARED) || (p->sharedMask & mask)==mask ); - /* Get shared locks at the system level, if necessary */ - if( rc==SQLITE_OK ){ - if( (allShared & mask)==0 ){ - rc = winShmSystemLock(pShmNode, WINSHM_RDLCK, ofst+WIN_SHM_BASE, n); - }else{ - rc = SQLITE_OK; - } - } + rc = winHandleUnlock(p->hShm, ofst+WIN_SHM_BASE, n); - /* Get the local shared locks */ - if( rc==SQLITE_OK ){ - p->sharedMask |= mask; - } - }else{ - /* Make sure no sibling connections hold locks that will block this - ** lock. If any do, return SQLITE_BUSY right away. - */ - for(pX=pShmNode->pFirst; pX; pX=pX->pNext){ - if( (pX->exclMask & mask)!=0 || (pX->sharedMask & mask)!=0 ){ - rc = SQLITE_BUSY; - break; + /* If successful, also clear the bits in sharedMask/exclMask */ + if( rc==SQLITE_OK ){ + p->exclMask = (p->exclMask & ~mask); + p->sharedMask = (p->sharedMask & ~mask); } - } - - /* Get the exclusive locks at the system level. Then if successful - ** also mark the local connection as being locked. - */ - if( rc==SQLITE_OK ){ - rc = winShmSystemLock(pShmNode, WINSHM_WRLCK, ofst+WIN_SHM_BASE, n); + }else{ + int bExcl = ((flags & SQLITE_SHM_EXCLUSIVE) ? 1 : 0); + DWORD nMs = winFileBusyTimeout(pDbFd); + rc = winHandleLockTimeout(p->hShm, ofst+WIN_SHM_BASE, n, bExcl, nMs); if( rc==SQLITE_OK ){ - assert( (p->sharedMask & mask)==0 ); - p->exclMask |= mask; + if( bExcl ){ + p->exclMask = (p->exclMask | mask); + }else{ + p->sharedMask = (p->sharedMask | mask); + } } } } - sqlite3_mutex_leave(pShmNode->mutex); - OSTRACE(("SHM-LOCK pid=%lu, id=%d, sharedMask=%03x, exclMask=%03x, rc=%s\n", - osGetCurrentProcessId(), p->id, p->sharedMask, p->exclMask, - sqlite3ErrName(rc))); + + OSTRACE(( + "SHM-LOCK(%d,%d,%d) pid=%lu, id=%d, sharedMask=%03x, exclMask=%03x," + " rc=%s\n", + ofst, n, flags, + osGetCurrentProcessId(), p->id, p->sharedMask, p->exclMask, + sqlite3ErrName(rc)) + ); return rc; } @@ -51108,13 +51794,15 @@ static int winShmMap( sqlite3_mutex_enter(pShmNode->mutex); if( pShmNode->isUnlocked ){ - rc = winLockSharedMemory(pShmNode); + /* Take the DMS lock. */ + assert( pShmNode->nRegion==0 ); + rc = winLockSharedMemory(pShmNode, winFileBusyTimeout(pDbFd)); if( rc!=SQLITE_OK ) goto shmpage_out; - pShmNode->isUnlocked = 0; } - assert( szRegion==pShmNode->szRegion || pShmNode->nRegion==0 ); + assert( szRegion==pShmNode->szRegion || pShmNode->nRegion==0 ); if( pShmNode->nRegion<=iRegion ){ + HANDLE hShared = pShmNode->hSharedShm; struct ShmRegion *apNew; /* New aRegion[] array */ int nByte = (iRegion+1)*szRegion; /* Minimum required file size */ sqlite3_int64 sz; /* Current size of wal-index file */ @@ -51125,10 +51813,9 @@ static int winShmMap( ** Check to see if it has been allocated (i.e. if the wal-index file is ** large enough to contain the requested region). */ - rc = winFileSize((sqlite3_file *)&pShmNode->hFile, &sz); + rc = winHandleSize(hShared, &sz); if( rc!=SQLITE_OK ){ - rc = winLogError(SQLITE_IOERR_SHMSIZE, osGetLastError(), - "winShmMap1", pDbFd->zPath); + rc = winLogError(rc, osGetLastError(), "winShmMap1", pDbFd->zPath); goto shmpage_out; } @@ -51137,19 +51824,17 @@ static int winShmMap( ** zero, exit early. *pp will be set to NULL and SQLITE_OK returned. ** ** Alternatively, if isWrite is non-zero, use ftruncate() to allocate - ** the requested memory region. - */ + ** the requested memory region. */ if( !isWrite ) goto shmpage_out; - rc = winTruncate((sqlite3_file *)&pShmNode->hFile, nByte); + rc = winHandleTruncate(hShared, nByte); if( rc!=SQLITE_OK ){ - rc = winLogError(SQLITE_IOERR_SHMSIZE, osGetLastError(), - "winShmMap2", pDbFd->zPath); + rc = winLogError(rc, osGetLastError(), "winShmMap2", pDbFd->zPath); goto shmpage_out; } } /* Map the requested memory region into this processes address space. */ - apNew = (struct ShmRegion *)sqlite3_realloc64( + apNew = (struct ShmRegion*)sqlite3_realloc64( pShmNode->aRegion, (iRegion+1)*sizeof(apNew[0]) ); if( !apNew ){ @@ -51168,18 +51853,13 @@ static int winShmMap( void *pMap = 0; /* Mapped memory region */ #if SQLITE_OS_WINRT - hMap = osCreateFileMappingFromApp(pShmNode->hFile.h, - NULL, protect, nByte, NULL - ); + hMap = osCreateFileMappingFromApp(hShared, NULL, protect, nByte, NULL); #elif defined(SQLITE_WIN32_HAS_WIDE) - hMap = osCreateFileMappingW(pShmNode->hFile.h, - NULL, protect, 0, nByte, NULL - ); + hMap = osCreateFileMappingW(hShared, NULL, protect, 0, nByte, NULL); #elif defined(SQLITE_WIN32_HAS_ANSI) && SQLITE_WIN32_CREATEFILEMAPPINGA - hMap = osCreateFileMappingA(pShmNode->hFile.h, - NULL, protect, 0, nByte, NULL - ); + hMap = osCreateFileMappingA(hShared, NULL, protect, 0, nByte, NULL); #endif + OSTRACE(("SHM-MAP-CREATE pid=%lu, region=%d, size=%d, rc=%s\n", osGetCurrentProcessId(), pShmNode->nRegion, nByte, hMap ? "ok" : "failed")); @@ -51222,7 +51902,9 @@ static int winShmMap( }else{ *pp = 0; } - if( pShmNode->isReadonly && rc==SQLITE_OK ) rc = SQLITE_READONLY; + if( pShmNode->isReadonly && rc==SQLITE_OK ){ + rc = SQLITE_READONLY; + } sqlite3_mutex_leave(pShmNode->mutex); return rc; } @@ -51542,47 +52224,6 @@ static winVfsAppData winNolockAppData = { ** sqlite3_vfs object. */ -#if defined(__CYGWIN__) -/* -** Convert a filename from whatever the underlying operating system -** supports for filenames into UTF-8. Space to hold the result is -** obtained from malloc and must be freed by the calling function. -*/ -static char *winConvertToUtf8Filename(const void *zFilename){ - char *zConverted = 0; - if( osIsNT() ){ - zConverted = winUnicodeToUtf8(zFilename); - } -#ifdef SQLITE_WIN32_HAS_ANSI - else{ - zConverted = winMbcsToUtf8(zFilename, osAreFileApisANSI()); - } -#endif - /* caller will handle out of memory */ - return zConverted; -} -#endif - -/* -** Convert a UTF-8 filename into whatever form the underlying -** operating system wants filenames in. Space to hold the result -** is obtained from malloc and must be freed by the calling -** function. -*/ -static void *winConvertFromUtf8Filename(const char *zFilename){ - void *zConverted = 0; - if( osIsNT() ){ - zConverted = winUtf8ToUnicode(zFilename); - } -#ifdef SQLITE_WIN32_HAS_ANSI - else{ - zConverted = winUtf8ToMbcs(zFilename, osAreFileApisANSI()); - } -#endif - /* caller will handle out of memory */ - return zConverted; -} - /* ** This function returns non-zero if the specified UTF-8 string buffer ** ends with a directory separator character or one was successfully @@ -51595,7 +52236,14 @@ static int winMakeEndInDirSep(int nBuf, char *zBuf){ if( winIsDirSep(zBuf[nLen-1]) ){ return 1; }else if( nLen+1mxPathname; nBuf = nMax + 2; + nMax = pVfs->mxPathname; + nBuf = 2 + (i64)nMax; zBuf = sqlite3MallocZero( nBuf ); if( !zBuf ){ OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n")); @@ -51672,7 +52321,7 @@ static int winGetTempname(sqlite3_vfs *pVfs, char **pzBuf){ } #if defined(__CYGWIN__) - else{ + else if( osGetenv!=NULL ){ static const char *azDirs[] = { 0, /* getenv("SQLITE_TMPDIR") */ 0, /* getenv("TMPDIR") */ @@ -51688,11 +52337,11 @@ static int winGetTempname(sqlite3_vfs *pVfs, char **pzBuf){ unsigned int i; const char *zDir = 0; - if( !azDirs[0] ) azDirs[0] = getenv("SQLITE_TMPDIR"); - if( !azDirs[1] ) azDirs[1] = getenv("TMPDIR"); - if( !azDirs[2] ) azDirs[2] = getenv("TMP"); - if( !azDirs[3] ) azDirs[3] = getenv("TEMP"); - if( !azDirs[4] ) azDirs[4] = getenv("USERPROFILE"); + if( !azDirs[0] ) azDirs[0] = osGetenv("SQLITE_TMPDIR"); + if( !azDirs[1] ) azDirs[1] = osGetenv("TMPDIR"); + if( !azDirs[2] ) azDirs[2] = osGetenv("TMP"); + if( !azDirs[3] ) azDirs[3] = osGetenv("TEMP"); + if( !azDirs[4] ) azDirs[4] = osGetenv("USERPROFILE"); for(i=0; inOut ){ + /* SQLite assumes that xFullPathname() nul-terminates the output buffer + ** even if it returns an error. */ + zOut[iOff] = '\0'; + return SQLITE_CANTOPEN_BKPT; + } + sqlite3_snprintf(nOut-iOff, &zOut[iOff], "%s", zPath); + return SQLITE_OK; +} +#endif /* __CYGWIN__ */ /* ** Turn a relative pathname into a full pathname. Write the full @@ -52475,8 +53173,8 @@ static int winFullPathnameNoMutex( int nFull, /* Size of output buffer in bytes */ char *zFull /* Output buffer */ ){ -#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && !defined(__CYGWIN__) - DWORD nByte; +#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT + int nByte; void *zConverted; char *zOut; #endif @@ -52489,64 +53187,82 @@ static int winFullPathnameNoMutex( zRelative++; } -#if defined(__CYGWIN__) SimulateIOError( return SQLITE_ERROR ); - UNUSED_PARAMETER(nFull); - assert( nFull>=pVfs->mxPathname ); - if ( sqlite3_data_directory && !winIsVerbatimPathname(zRelative) ){ - /* - ** NOTE: We are dealing with a relative path name and the data - ** directory has been set. Therefore, use it as the basis - ** for converting the relative path name to an absolute - ** one by prepending the data directory and a slash. - */ - char *zOut = sqlite3MallocZero( pVfs->mxPathname+1 ); - if( !zOut ){ - return SQLITE_IOERR_NOMEM_BKPT; - } - if( cygwin_conv_path( - (osIsNT() ? CCP_POSIX_TO_WIN_W : CCP_POSIX_TO_WIN_A) | - CCP_RELATIVE, zRelative, zOut, pVfs->mxPathname+1)<0 ){ - sqlite3_free(zOut); - return winLogError(SQLITE_CANTOPEN_CONVPATH, (DWORD)errno, - "winFullPathname1", zRelative); - }else{ - char *zUtf8 = winConvertToUtf8Filename(zOut); - if( !zUtf8 ){ - sqlite3_free(zOut); - return SQLITE_IOERR_NOMEM_BKPT; - } - sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s%c%s", - sqlite3_data_directory, winGetDirSep(), zUtf8); - sqlite3_free(zUtf8); - sqlite3_free(zOut); - } - }else{ - char *zOut = sqlite3MallocZero( pVfs->mxPathname+1 ); - if( !zOut ){ - return SQLITE_IOERR_NOMEM_BKPT; - } - if( cygwin_conv_path( - (osIsNT() ? CCP_POSIX_TO_WIN_W : CCP_POSIX_TO_WIN_A), - zRelative, zOut, pVfs->mxPathname+1)<0 ){ - sqlite3_free(zOut); - return winLogError(SQLITE_CANTOPEN_CONVPATH, (DWORD)errno, - "winFullPathname2", zRelative); - }else{ - char *zUtf8 = winConvertToUtf8Filename(zOut); - if( !zUtf8 ){ - sqlite3_free(zOut); - return SQLITE_IOERR_NOMEM_BKPT; - } - sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s", zUtf8); - sqlite3_free(zUtf8); - sqlite3_free(zOut); + +#ifdef __CYGWIN__ + if( osGetcwd ){ + zFull[nFull-1] = '\0'; + if( !winIsDriveLetterAndColon(zRelative) || !winIsDirSep(zRelative[2]) ){ + int rc = SQLITE_OK; + int nLink = 1; /* Number of symbolic links followed so far */ + const char *zIn = zRelative; /* Input path for each iteration of loop */ + char *zDel = 0; + struct stat buf; + + UNUSED_PARAMETER(pVfs); + + do { + /* Call lstat() on path zIn. Set bLink to true if the path is a symbolic + ** link, or false otherwise. */ + int bLink = 0; + if( osLstat && osReadlink ) { + if( osLstat(zIn, &buf)!=0 ){ + int myErrno = osErrno; + if( myErrno!=ENOENT ){ + rc = winLogError(SQLITE_CANTOPEN_BKPT, (DWORD)myErrno, "lstat", zIn); + } + }else{ + bLink = ((buf.st_mode & 0170000) == 0120000); + } + + if( bLink ){ + if( zDel==0 ){ + zDel = sqlite3MallocZero(nFull); + if( zDel==0 ) rc = SQLITE_NOMEM; + }else if( ++nLink>SQLITE_MAX_SYMLINKS ){ + rc = SQLITE_CANTOPEN_BKPT; + } + + if( rc==SQLITE_OK ){ + nByte = osReadlink(zIn, zDel, nFull-1); + if( nByte ==(DWORD)-1 ){ + rc = winLogError(SQLITE_CANTOPEN_BKPT, (DWORD)osErrno, "readlink", zIn); + }else{ + if( zDel[0]!='/' ){ + int n; + for(n = sqlite3Strlen30(zIn); n>0 && zIn[n-1]!='/'; n--); + if( nByte+n+1>nFull ){ + rc = SQLITE_CANTOPEN_BKPT; + }else{ + memmove(&zDel[n], zDel, nByte+1); + memcpy(zDel, zIn, n); + nByte += n; + } + } + zDel[nByte] = '\0'; + } + } + + zIn = zDel; + } + } + + assert( rc!=SQLITE_OK || zIn!=zFull || zIn[0]=='/' ); + if( rc==SQLITE_OK && zIn!=zFull ){ + rc = mkFullPathname(zIn, zFull, nFull); + } + if( bLink==0 ) break; + zIn = zFull; + }while( rc==SQLITE_OK ); + + sqlite3_free(zDel); + winSimplifyName(zFull); + return rc; } } - return SQLITE_OK; -#endif +#endif /* __CYGWIN__ */ -#if (SQLITE_OS_WINCE || SQLITE_OS_WINRT) && !defined(__CYGWIN__) +#if (SQLITE_OS_WINCE || SQLITE_OS_WINRT) && defined(_WIN32) SimulateIOError( return SQLITE_ERROR ); /* WinCE has no concept of a relative pathname, or so I am told. */ /* WinRT has no way to convert a relative path to an absolute one. */ @@ -52565,7 +53281,8 @@ static int winFullPathnameNoMutex( return SQLITE_OK; #endif -#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && !defined(__CYGWIN__) +#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT +#if defined(_WIN32) /* It's odd to simulate an io-error here, but really this is just ** using the io-error infrastructure to test that SQLite handles this ** function failing. This function could fail if, for example, the @@ -52583,6 +53300,7 @@ static int winFullPathnameNoMutex( sqlite3_data_directory, winGetDirSep(), zRelative); return SQLITE_OK; } +#endif zConverted = winConvertFromUtf8Filename(zRelative); if( zConverted==0 ){ return SQLITE_IOERR_NOMEM_BKPT; @@ -52621,13 +53339,12 @@ static int winFullPathnameNoMutex( return winLogError(SQLITE_CANTOPEN_FULLPATH, osGetLastError(), "winFullPathname3", zRelative); } - nByte += 3; - zTemp = sqlite3MallocZero( nByte*sizeof(zTemp[0]) ); + zTemp = sqlite3MallocZero( nByte*sizeof(zTemp[0]) + 3*sizeof(zTemp[0]) ); if( zTemp==0 ){ sqlite3_free(zConverted); return SQLITE_IOERR_NOMEM_BKPT; } - nByte = osGetFullPathNameA((char*)zConverted, nByte, zTemp, 0); + nByte = osGetFullPathNameA((char*)zConverted, nByte+3, zTemp, 0); if( nByte==0 ){ sqlite3_free(zConverted); sqlite3_free(zTemp); @@ -52640,7 +53357,26 @@ static int winFullPathnameNoMutex( } #endif if( zOut ){ +#ifdef __CYGWIN__ + if( memcmp(zOut, "\\\\?\\", 4) ){ + sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s", zOut); + }else if( memcmp(zOut+4, "UNC\\", 4) ){ + sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s", zOut+4); + }else{ + char *p = zOut+6; + *p = '\\'; + if( osGetcwd ){ + /* On Cygwin, UNC paths use forward slashes */ + while( *p ){ + if( *p=='\\' ) *p = '/'; + ++p; + } + } + sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s", zOut+6); + } +#else sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s", zOut); +#endif /* __CYGWIN__ */ sqlite3_free(zOut); return SQLITE_OK; }else{ @@ -52670,25 +53406,8 @@ static int winFullPathname( */ static void *winDlOpen(sqlite3_vfs *pVfs, const char *zFilename){ HANDLE h; -#if defined(__CYGWIN__) - int nFull = pVfs->mxPathname+1; - char *zFull = sqlite3MallocZero( nFull ); - void *zConverted = 0; - if( zFull==0 ){ - OSTRACE(("DLOPEN name=%s, handle=%p\n", zFilename, (void*)0)); - return 0; - } - if( winFullPathname(pVfs, zFilename, nFull, zFull)!=SQLITE_OK ){ - sqlite3_free(zFull); - OSTRACE(("DLOPEN name=%s, handle=%p\n", zFilename, (void*)0)); - return 0; - } - zConverted = winConvertFromUtf8Filename(zFull); - sqlite3_free(zFull); -#else void *zConverted = winConvertFromUtf8Filename(zFilename); UNUSED_PARAMETER(pVfs); -#endif if( zConverted==0 ){ OSTRACE(("DLOPEN name=%s, handle=%p\n", zFilename, (void*)0)); return 0; @@ -53037,7 +53756,7 @@ SQLITE_API int sqlite3_os_init(void){ /* Double-check that the aSyscall[] array has been constructed ** correctly. See ticket [bb3a86e890c8e96ab] */ - assert( ArraySize(aSyscall)==80 ); + assert( ArraySize(aSyscall)==89 ); /* get memory map allocation granularity */ memset(&winSysInfo, 0, sizeof(SYSTEM_INFO)); @@ -53656,13 +54375,13 @@ static int memdbOpen( } if( p==0 ){ MemStore **apNew; - p = sqlite3Malloc( sizeof(*p) + szName + 3 ); + p = sqlite3Malloc( sizeof(*p) + (i64)szName + 3 ); if( p==0 ){ sqlite3_mutex_leave(pVfsMutex); return SQLITE_NOMEM; } apNew = sqlite3Realloc(memdb_g.apMemStore, - sizeof(apNew[0])*(memdb_g.nMemStore+1) ); + sizeof(apNew[0])*(1+(i64)memdb_g.nMemStore) ); if( apNew==0 ){ sqlite3_free(p); sqlite3_mutex_leave(pVfsMutex); @@ -54095,7 +54814,7 @@ SQLITE_PRIVATE int sqlite3MemdbInit(void){ ** no fewer collisions than the no-op *1. */ #define BITVEC_HASH(X) (((X)*1)%BITVEC_NINT) -#define BITVEC_NPTR (BITVEC_USIZE/sizeof(Bitvec *)) +#define BITVEC_NPTR ((u32)(BITVEC_USIZE/sizeof(Bitvec *))) /* @@ -54278,7 +54997,7 @@ SQLITE_PRIVATE void sqlite3BitvecClear(Bitvec *p, u32 i, void *pBuf){ } } if( p->iSize<=BITVEC_NBIT ){ - p->u.aBitmap[i/BITVEC_SZELEM] &= ~(1 << (i&(BITVEC_SZELEM-1))); + p->u.aBitmap[i/BITVEC_SZELEM] &= ~(BITVEC_TELEM)(1<<(i&(BITVEC_SZELEM-1))); }else{ unsigned int j; u32 *aiValues = pBuf; @@ -54329,7 +55048,7 @@ SQLITE_PRIVATE u32 sqlite3BitvecSize(Bitvec *p){ ** individual bits within V. */ #define SETBIT(V,I) V[I>>3] |= (1<<(I&7)) -#define CLEARBIT(V,I) V[I>>3] &= ~(1<<(I&7)) +#define CLEARBIT(V,I) V[I>>3] &= ~(BITVEC_TELEM)(1<<(I&7)) #define TESTBIT(V,I) (V[I>>3]&(1<<(I&7)))!=0 /* @@ -54372,7 +55091,7 @@ SQLITE_PRIVATE int sqlite3BitvecBuiltinTest(int sz, int *aOp){ /* Allocate the Bitvec to be tested and a linear array of ** bits to act as the reference */ pBitvec = sqlite3BitvecCreate( sz ); - pV = sqlite3MallocZero( (sz+7)/8 + 1 ); + pV = sqlite3MallocZero( (7+(i64)sz)/8 + 1 ); pTmpSpace = sqlite3_malloc64(BITVEC_SZ); if( pBitvec==0 || pV==0 || pTmpSpace==0 ) goto bitvec_end; @@ -55613,10 +56332,6 @@ static SQLITE_WSD struct PCacheGlobal { sqlite3_mutex *mutex; /* Mutex for accessing the following: */ PgFreeslot *pFree; /* Free page blocks */ int nFreeSlot; /* Number of unused pcache slots */ - /* The following value requires a mutex to change. We skip the mutex on - ** reading because (1) most platforms read a 32-bit integer atomically and - ** (2) even if an incorrect value is read, no great harm is done since this - ** is really just an optimization. */ int bUnderPressure; /* True if low on PAGECACHE memory */ } pcache1_g; @@ -55664,7 +56379,7 @@ SQLITE_PRIVATE void sqlite3PCacheBufferSetup(void *pBuf, int sz, int n){ pcache1.nReserve = n>90 ? 10 : (n/10 + 1); pcache1.pStart = pBuf; pcache1.pFree = 0; - pcache1.bUnderPressure = 0; + AtomicStore(&pcache1.bUnderPressure,0); while( n-- ){ p = (PgFreeslot*)pBuf; p->pNext = pcache1.pFree; @@ -55732,7 +56447,7 @@ static void *pcache1Alloc(int nByte){ if( p ){ pcache1.pFree = pcache1.pFree->pNext; pcache1.nFreeSlot--; - pcache1.bUnderPressure = pcache1.nFreeSlot=0 ); sqlite3StatusHighwater(SQLITE_STATUS_PAGECACHE_SIZE, nByte); sqlite3StatusUp(SQLITE_STATUS_PAGECACHE_USED, 1); @@ -55771,7 +56486,7 @@ static void pcache1Free(void *p){ pSlot->pNext = pcache1.pFree; pcache1.pFree = pSlot; pcache1.nFreeSlot++; - pcache1.bUnderPressure = pcache1.nFreeSlotszPage+pCache->szExtra)<=pcache1.szSlot ){ - return pcache1.bUnderPressure; + return AtomicLoad(&pcache1.bUnderPressure); }else{ return sqlite3HeapNearlyFull(); } @@ -55919,12 +56634,12 @@ static int pcache1UnderMemoryPressure(PCache1 *pCache){ */ static void pcache1ResizeHash(PCache1 *p){ PgHdr1 **apNew; - unsigned int nNew; - unsigned int i; + u64 nNew; + u32 i; assert( sqlite3_mutex_held(p->pGroup->mutex) ); - nNew = p->nHash*2; + nNew = 2*(u64)p->nHash; if( nNew<256 ){ nNew = 256; } @@ -56147,7 +56862,7 @@ static void pcache1Destroy(sqlite3_pcache *p); static sqlite3_pcache *pcache1Create(int szPage, int szExtra, int bPurgeable){ PCache1 *pCache; /* The newly created page cache */ PGroup *pGroup; /* The group the new page cache will belong to */ - int sz; /* Bytes of memory required to allocate the new cache */ + i64 sz; /* Bytes of memory required to allocate the new cache */ assert( (szPage & (szPage-1))==0 && szPage>=512 && szPage<=65536 ); assert( szExtra < 300 ); @@ -58626,7 +59341,7 @@ static void checkPage(PgHdr *pPg){ ** If an error occurs while reading from the journal file, an SQLite ** error code is returned. */ -static int readSuperJournal(sqlite3_file *pJrnl, char *zSuper, u32 nSuper){ +static int readSuperJournal(sqlite3_file *pJrnl, char *zSuper, u64 nSuper){ int rc; /* Return code */ u32 len; /* Length in bytes of super-journal name */ i64 szJ; /* Total size in bytes of journal file pJrnl */ @@ -59181,6 +59896,15 @@ static void pager_unlock(Pager *pPager){ if( pagerUseWal(pPager) ){ assert( !isOpen(pPager->jfd) ); + if( pPager->eState==PAGER_ERROR ){ + /* If an IO error occurs in wal.c while attempting to wrap the wal file, + ** then the Wal object may be holding a write-lock but no read-lock. + ** This call ensures that the write-lock is dropped as well. We cannot + ** have sqlite3WalEndReadTransaction() drop the write-lock, as it once + ** did, because this would break "BEGIN EXCLUSIVE" handling for + ** SQLITE_ENABLE_SETLK_TIMEOUT builds. */ + sqlite3WalEndWriteTransaction(pPager->pWal); + } sqlite3WalEndReadTransaction(pPager->pWal); pPager->eState = PAGER_OPEN; }else if( !pPager->exclusiveMode ){ @@ -59862,12 +60586,12 @@ static int pager_delsuper(Pager *pPager, const char *zSuper){ char *zJournal; /* Pointer to one journal within MJ file */ char *zSuperPtr; /* Space to hold super-journal filename */ char *zFree = 0; /* Free this buffer */ - int nSuperPtr; /* Amount of space allocated to zSuperPtr[] */ + i64 nSuperPtr; /* Amount of space allocated to zSuperPtr[] */ /* Allocate space for both the pJournal and pSuper file descriptors. ** If successful, open the super-journal file for reading. */ - pSuper = (sqlite3_file *)sqlite3MallocZero(pVfs->szOsFile * 2); + pSuper = (sqlite3_file *)sqlite3MallocZero(2 * (i64)pVfs->szOsFile); if( !pSuper ){ rc = SQLITE_NOMEM_BKPT; pJournal = 0; @@ -59885,11 +60609,14 @@ static int pager_delsuper(Pager *pPager, const char *zSuper){ */ rc = sqlite3OsFileSize(pSuper, &nSuperJournal); if( rc!=SQLITE_OK ) goto delsuper_out; - nSuperPtr = pVfs->mxPathname+1; + nSuperPtr = 1 + (i64)pVfs->mxPathname; + assert( nSuperJournal>=0 && nSuperPtr>0 ); zFree = sqlite3Malloc(4 + nSuperJournal + nSuperPtr + 2); if( !zFree ){ rc = SQLITE_NOMEM_BKPT; goto delsuper_out; + }else{ + assert( nSuperJournal<=0x7fffffff ); } zFree[0] = zFree[1] = zFree[2] = zFree[3] = 0; zSuperJournal = &zFree[4]; @@ -60150,7 +60877,7 @@ static int pager_playback(Pager *pPager, int isHot){ ** for pageSize. */ zSuper = pPager->pTmpSpace; - rc = readSuperJournal(pPager->jfd, zSuper, pPager->pVfs->mxPathname+1); + rc = readSuperJournal(pPager->jfd, zSuper, 1+(i64)pPager->pVfs->mxPathname); if( rc==SQLITE_OK && zSuper[0] ){ rc = sqlite3OsAccess(pVfs, zSuper, SQLITE_ACCESS_EXISTS, &res); } @@ -60289,7 +61016,7 @@ static int pager_playback(Pager *pPager, int isHot){ ** which case it requires 4 0x00 bytes in memory immediately before ** the filename. */ zSuper = &pPager->pTmpSpace[4]; - rc = readSuperJournal(pPager->jfd, zSuper, pPager->pVfs->mxPathname+1); + rc = readSuperJournal(pPager->jfd, zSuper, 1+(i64)pPager->pVfs->mxPathname); testcase( rc!=SQLITE_OK ); } if( rc==SQLITE_OK @@ -62060,6 +62787,7 @@ SQLITE_PRIVATE int sqlite3PagerOpen( const char *zUri = 0; /* URI args to copy */ int nUriByte = 1; /* Number of bytes of URI args at *zUri */ + /* Figure out how much space is required for each journal file-handle ** (there are two of them, the main journal and the sub-journal). */ journalFileSize = ROUND8(sqlite3JournalSize(pVfs)); @@ -62085,8 +62813,8 @@ SQLITE_PRIVATE int sqlite3PagerOpen( */ if( zFilename && zFilename[0] ){ const char *z; - nPathname = pVfs->mxPathname+1; - zPathname = sqlite3DbMallocRaw(0, nPathname*2); + nPathname = pVfs->mxPathname + 1; + zPathname = sqlite3DbMallocRaw(0, 2*(i64)nPathname); if( zPathname==0 ){ return SQLITE_NOMEM_BKPT; } @@ -62173,14 +62901,14 @@ SQLITE_PRIVATE int sqlite3PagerOpen( ROUND8(sizeof(*pPager)) + /* Pager structure */ ROUND8(pcacheSize) + /* PCache object */ ROUND8(pVfs->szOsFile) + /* The main db file */ - journalFileSize * 2 + /* The two journal files */ + (u64)journalFileSize * 2 + /* The two journal files */ SQLITE_PTRSIZE + /* Space to hold a pointer */ 4 + /* Database prefix */ - nPathname + 1 + /* database filename */ - nUriByte + /* query parameters */ - nPathname + 8 + 1 + /* Journal filename */ + (u64)nPathname + 1 + /* database filename */ + (u64)nUriByte + /* query parameters */ + (u64)nPathname + 8 + 1 + /* Journal filename */ #ifndef SQLITE_OMIT_WAL - nPathname + 4 + 1 + /* WAL filename */ + (u64)nPathname + 4 + 1 + /* WAL filename */ #endif 3 /* Terminator */ ); @@ -65635,6 +66363,11 @@ struct WalCkptInfo { /* ** An open write-ahead log file is represented by an instance of the ** following object. +** +** writeLock: +** This is usually set to 1 whenever the WRITER lock is held. However, +** if it is set to 2, then the WRITER lock is held but must be released +** by walHandleException() if a SEH exception is thrown. */ struct Wal { sqlite3_vfs *pVfs; /* The VFS used to create pDbFd */ @@ -65725,9 +66458,13 @@ struct WalIterator { u32 *aPgno; /* Array of page numbers. */ int nEntry; /* Nr. of entries in aPgno[] and aIndex[] */ int iZero; /* Frame number associated with aPgno[0] */ - } aSegment[1]; /* One for every 32KB page in the wal-index */ + } aSegment[FLEXARRAY]; /* One for every 32KB page in the wal-index */ }; +/* Size (in bytes) of a WalIterator object suitable for N or fewer segments */ +#define SZ_WALITERATOR(N) \ + (offsetof(WalIterator,aSegment)*(N)*sizeof(struct WalSegment)) + /* ** Define the parameters of the hash tables in the wal-index file. There ** is a hash-table following every HASHTABLE_NPAGE page numbers in the @@ -65886,7 +66623,7 @@ static SQLITE_NOINLINE int walIndexPageRealloc( /* Enlarge the pWal->apWiData[] array if required */ if( pWal->nWiData<=iPage ){ - sqlite3_int64 nByte = sizeof(u32*)*(iPage+1); + sqlite3_int64 nByte = sizeof(u32*)*(1+(i64)iPage); volatile u32 **apNew; apNew = (volatile u32 **)sqlite3Realloc((void *)pWal->apWiData, nByte); if( !apNew ){ @@ -65995,10 +66732,8 @@ static void walChecksumBytes( s1 = s2 = 0; } - assert( nByte>=8 ); - assert( (nByte&0x00000007)==0 ); - assert( nByte<=65536 ); - assert( nByte%4==0 ); + /* nByte is a multiple of 8 between 8 and 65536 */ + assert( nByte>=8 && (nByte&7)==0 && nByte<=65536 ); if( !nativeCksum ){ do { @@ -67088,8 +67823,7 @@ static int walIteratorInit(Wal *pWal, u32 nBackfill, WalIterator **pp){ /* Allocate space for the WalIterator object. */ nSegment = walFramePage(iLast) + 1; - nByte = sizeof(WalIterator) - + (nSegment-1)*sizeof(struct WalSegment) + nByte = SZ_WALITERATOR(nSegment) + iLast*sizeof(ht_slot); p = (WalIterator *)sqlite3_malloc64(nByte + sizeof(ht_slot) * (iLast>HASHTABLE_NPAGE?HASHTABLE_NPAGE:iLast) @@ -67160,7 +67894,7 @@ static int walEnableBlockingMs(Wal *pWal, int nMs){ static int walEnableBlocking(Wal *pWal){ int res = 0; if( pWal->db ){ - int tmout = pWal->db->busyTimeout; + int tmout = pWal->db->setlkTimeout; if( tmout ){ res = walEnableBlockingMs(pWal, tmout); } @@ -67546,7 +68280,9 @@ static int walHandleException(Wal *pWal){ static const int S = 1; static const int E = (1<lockMask & ~( + u32 mUnlock; + if( pWal->writeLock==2 ) pWal->writeLock = 0; + mUnlock = pWal->lockMask & ~( (pWal->readLock<0 ? 0 : (S << WAL_READ_LOCK(pWal->readLock))) | (pWal->writeLock ? (E << WAL_WRITE_LOCK) : 0) | (pWal->ckptLock ? (E << WAL_CKPT_LOCK) : 0) @@ -67818,7 +68554,12 @@ static int walIndexReadHdr(Wal *pWal, int *pChanged){ if( bWriteLock || SQLITE_OK==(rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1)) ){ - pWal->writeLock = 1; + /* If the write-lock was just obtained, set writeLock to 2 instead of + ** the usual 1. This causes walIndexPage() to behave as if the + ** write-lock were held (so that it allocates new pages as required), + ** and walHandleException() to unlock the write-lock if a SEH exception + ** is thrown. */ + if( !bWriteLock ) pWal->writeLock = 2; if( SQLITE_OK==(rc = walIndexPage(pWal, 0, &page0)) ){ badHdr = walIndexTryHdr(pWal, pChanged); if( badHdr ){ @@ -68603,8 +69344,11 @@ SQLITE_PRIVATE int sqlite3WalBeginReadTransaction(Wal *pWal, int *pChanged){ ** read-lock. */ SQLITE_PRIVATE void sqlite3WalEndReadTransaction(Wal *pWal){ - sqlite3WalEndWriteTransaction(pWal); +#ifndef SQLITE_ENABLE_SETLK_TIMEOUT + assert( pWal->writeLock==0 || pWal->readLock<0 ); +#endif if( pWal->readLock>=0 ){ + sqlite3WalEndWriteTransaction(pWal); walUnlockShared(pWal, WAL_READ_LOCK(pWal->readLock)); pWal->readLock = -1; } @@ -68797,7 +69541,7 @@ SQLITE_PRIVATE int sqlite3WalBeginWriteTransaction(Wal *pWal){ ** read-transaction was even opened, making this call a no-op. ** Return early. */ if( pWal->writeLock ){ - assert( !memcmp(&pWal->hdr,(void *)walIndexHdr(pWal),sizeof(WalIndexHdr)) ); + assert( !memcmp(&pWal->hdr,(void*)pWal->apWiData[0],sizeof(WalIndexHdr)) ); return SQLITE_OK; } #endif @@ -70246,6 +70990,12 @@ struct CellInfo { */ #define BTCURSOR_MAX_DEPTH 20 +/* +** Maximum amount of storage local to a database page, regardless of +** page size. +*/ +#define BT_MAX_LOCAL 65501 /* 65536 - 35 */ + /* ** A cursor is a pointer to a particular entry within a particular ** b-tree within a database file. @@ -70654,7 +71404,7 @@ SQLITE_PRIVATE int sqlite3BtreeHoldsMutex(Btree *p){ */ static void SQLITE_NOINLINE btreeEnterAll(sqlite3 *db){ int i; - int skipOk = 1; + u8 skipOk = 1; Btree *p; assert( sqlite3_mutex_held(db->mutex) ); for(i=0; inDb; i++){ @@ -71510,7 +72260,7 @@ static int saveCursorKey(BtCursor *pCur){ ** below. */ void *pKey; pCur->nKey = sqlite3BtreePayloadSize(pCur); - pKey = sqlite3Malloc( pCur->nKey + 9 + 8 ); + pKey = sqlite3Malloc( ((i64)pCur->nKey) + 9 + 8 ); if( pKey ){ rc = sqlite3BtreePayload(pCur, 0, (int)pCur->nKey, pKey); if( rc==SQLITE_OK ){ @@ -71800,7 +72550,7 @@ SQLITE_PRIVATE void sqlite3BtreeCursorHint(BtCursor *pCur, int eHintType, ...){ */ SQLITE_PRIVATE void sqlite3BtreeCursorHintFlags(BtCursor *pCur, unsigned x){ assert( x==BTREE_SEEK_EQ || x==BTREE_BULKLOAD || x==0 ); - pCur->hints = x; + pCur->hints = (u8)x; } @@ -71994,14 +72744,15 @@ static SQLITE_NOINLINE void btreeParseCellAdjustSizeForOverflow( static int btreePayloadToLocal(MemPage *pPage, i64 nPayload){ int maxLocal; /* Maximum amount of payload held locally */ maxLocal = pPage->maxLocal; + assert( nPayload>=0 ); if( nPayload<=maxLocal ){ - return nPayload; + return (int)nPayload; }else{ int minLocal; /* Minimum amount of payload held locally */ int surplus; /* Overflow payload available for local storage */ minLocal = pPage->minLocal; - surplus = minLocal + (nPayload - minLocal)%(pPage->pBt->usableSize-4); - return ( surplus <= maxLocal ) ? surplus : minLocal; + surplus = (int)(minLocal +(nPayload - minLocal)%(pPage->pBt->usableSize-4)); + return (surplus <= maxLocal) ? surplus : minLocal; } } @@ -72111,11 +72862,13 @@ static void btreeParseCellPtr( pInfo->pPayload = pIter; testcase( nPayload==pPage->maxLocal ); testcase( nPayload==(u32)pPage->maxLocal+1 ); + assert( nPayload>=0 ); + assert( pPage->maxLocal <= BT_MAX_LOCAL ); if( nPayload<=pPage->maxLocal ){ /* This is the (easy) common case where the entire payload fits ** on the local page. No overflow is required. */ - pInfo->nSize = nPayload + (u16)(pIter - pCell); + pInfo->nSize = (u16)nPayload + (u16)(pIter - pCell); if( pInfo->nSize<4 ) pInfo->nSize = 4; pInfo->nLocal = (u16)nPayload; }else{ @@ -72148,11 +72901,13 @@ static void btreeParseCellPtrIndex( pInfo->pPayload = pIter; testcase( nPayload==pPage->maxLocal ); testcase( nPayload==(u32)pPage->maxLocal+1 ); + assert( nPayload>=0 ); + assert( pPage->maxLocal <= BT_MAX_LOCAL ); if( nPayload<=pPage->maxLocal ){ /* This is the (easy) common case where the entire payload fits ** on the local page. No overflow is required. */ - pInfo->nSize = nPayload + (u16)(pIter - pCell); + pInfo->nSize = (u16)nPayload + (u16)(pIter - pCell); if( pInfo->nSize<4 ) pInfo->nSize = 4; pInfo->nLocal = (u16)nPayload; }else{ @@ -72691,14 +73446,14 @@ static SQLITE_INLINE int allocateSpace(MemPage *pPage, int nByte, int *pIdx){ ** at the end of the page. So do additional corruption checks inside this ** routine and return SQLITE_CORRUPT if any problems are found. */ -static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){ - u16 iPtr; /* Address of ptr to next freeblock */ - u16 iFreeBlk; /* Address of the next freeblock */ +static int freeSpace(MemPage *pPage, int iStart, int iSize){ + int iPtr; /* Address of ptr to next freeblock */ + int iFreeBlk; /* Address of the next freeblock */ u8 hdr; /* Page header size. 0 or 100 */ - u8 nFrag = 0; /* Reduction in fragmentation */ - u16 iOrigSize = iSize; /* Original value of iSize */ - u16 x; /* Offset to cell content area */ - u32 iEnd = iStart + iSize; /* First byte past the iStart buffer */ + int nFrag = 0; /* Reduction in fragmentation */ + int iOrigSize = iSize; /* Original value of iSize */ + int x; /* Offset to cell content area */ + int iEnd = iStart + iSize; /* First byte past the iStart buffer */ unsigned char *data = pPage->aData; /* Page content */ u8 *pTmp; /* Temporary ptr into data[] */ @@ -72725,7 +73480,7 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){ } iPtr = iFreeBlk; } - if( iFreeBlk>pPage->pBt->usableSize-4 ){ /* TH3: corrupt081.100 */ + if( iFreeBlk>(int)pPage->pBt->usableSize-4 ){ /* TH3: corrupt081.100 */ return SQLITE_CORRUPT_PAGE(pPage); } assert( iFreeBlk>iPtr || iFreeBlk==0 || CORRUPT_DB ); @@ -72740,7 +73495,7 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){ nFrag = iFreeBlk - iEnd; if( iEnd>iFreeBlk ) return SQLITE_CORRUPT_PAGE(pPage); iEnd = iFreeBlk + get2byte(&data[iFreeBlk+2]); - if( iEnd > pPage->pBt->usableSize ){ + if( iEnd > (int)pPage->pBt->usableSize ){ return SQLITE_CORRUPT_PAGE(pPage); } iSize = iEnd - iStart; @@ -72761,7 +73516,7 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){ } } if( nFrag>data[hdr+7] ) return SQLITE_CORRUPT_PAGE(pPage); - data[hdr+7] -= nFrag; + data[hdr+7] -= (u8)nFrag; } pTmp = &data[hdr+5]; x = get2byte(pTmp); @@ -72782,7 +73537,8 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){ /* Insert the new freeblock into the freelist */ put2byte(&data[iPtr], iStart); put2byte(&data[iStart], iFreeBlk); - put2byte(&data[iStart+2], iSize); + assert( iSize>=0 && iSize<=0xffff ); + put2byte(&data[iStart+2], (u16)iSize); } pPage->nFree += iOrigSize; return SQLITE_OK; @@ -73008,7 +73764,7 @@ static int btreeInitPage(MemPage *pPage){ assert( pBt->pageSize>=512 && pBt->pageSize<=65536 ); pPage->maskPage = (u16)(pBt->pageSize - 1); pPage->nOverflow = 0; - pPage->cellOffset = pPage->hdrOffset + 8 + pPage->childPtrSize; + pPage->cellOffset = (u16)(pPage->hdrOffset + 8 + pPage->childPtrSize); pPage->aCellIdx = data + pPage->childPtrSize + 8; pPage->aDataEnd = pPage->aData + pBt->pageSize; pPage->aDataOfst = pPage->aData + pPage->childPtrSize; @@ -73042,8 +73798,8 @@ static int btreeInitPage(MemPage *pPage){ static void zeroPage(MemPage *pPage, int flags){ unsigned char *data = pPage->aData; BtShared *pBt = pPage->pBt; - u8 hdr = pPage->hdrOffset; - u16 first; + int hdr = pPage->hdrOffset; + int first; assert( sqlite3PagerPagenumber(pPage->pDbPage)==pPage->pgno || CORRUPT_DB ); assert( sqlite3PagerGetExtra(pPage->pDbPage) == (void*)pPage ); @@ -73060,7 +73816,7 @@ static void zeroPage(MemPage *pPage, int flags){ put2byte(&data[hdr+5], pBt->usableSize); pPage->nFree = (u16)(pBt->usableSize - first); decodeFlags(pPage, flags); - pPage->cellOffset = first; + pPage->cellOffset = (u16)first; pPage->aDataEnd = &data[pBt->pageSize]; pPage->aCellIdx = &data[first]; pPage->aDataOfst = &data[pPage->childPtrSize]; @@ -73846,7 +74602,7 @@ SQLITE_PRIVATE int sqlite3BtreeSetPageSize(Btree *p, int pageSize, int nReserve, BtShared *pBt = p->pBt; assert( nReserve>=0 && nReserve<=255 ); sqlite3BtreeEnter(p); - pBt->nReserveWanted = nReserve; + pBt->nReserveWanted = (u8)nReserve; x = pBt->pageSize - pBt->usableSize; if( nReservebtsFlags & BTS_PAGESIZE_FIXED ){ @@ -73952,7 +74708,7 @@ SQLITE_PRIVATE int sqlite3BtreeSecureDelete(Btree *p, int newFlag){ assert( BTS_FAST_SECURE==(BTS_OVERWRITE|BTS_SECURE_DELETE) ); if( newFlag>=0 ){ p->pBt->btsFlags &= ~BTS_FAST_SECURE; - p->pBt->btsFlags |= BTS_SECURE_DELETE*newFlag; + p->pBt->btsFlags |= (u16)(BTS_SECURE_DELETE*newFlag); } b = (p->pBt->btsFlags & BTS_FAST_SECURE)/BTS_SECURE_DELETE; sqlite3BtreeLeave(p); @@ -76881,7 +77637,7 @@ SQLITE_PRIVATE int sqlite3BtreeIndexMoveto( rc = SQLITE_CORRUPT_PAGE(pPage); goto moveto_index_finish; } - pCellKey = sqlite3Malloc( nCell+nOverrun ); + pCellKey = sqlite3Malloc( (u64)nCell+(u64)nOverrun ); if( pCellKey==0 ){ rc = SQLITE_NOMEM_BKPT; goto moveto_index_finish; @@ -78400,7 +79156,8 @@ static int rebuildPage( } /* The pPg->nFree field is now set incorrectly. The caller will fix it. */ - pPg->nCell = nCell; + assert( nCell < 10922 ); + pPg->nCell = (u16)nCell; pPg->nOverflow = 0; put2byte(&aData[hdr+1], 0); @@ -78647,9 +79404,13 @@ static int editPage( if( pageInsertArray( pPg, pBegin, &pData, pCellptr, iNew+nCell, nNew-nCell, pCArray - ) ) goto editpage_fail; + ) + ){ + goto editpage_fail; + } - pPg->nCell = nNew; + assert( nNew < 10922 ); + pPg->nCell = (u16)nNew; pPg->nOverflow = 0; put2byte(&aData[hdr+3], pPg->nCell); @@ -78958,7 +79719,7 @@ static int balance_nonroot( int pageFlags; /* Value of pPage->aData[0] */ int iSpace1 = 0; /* First unused byte of aSpace1[] */ int iOvflSpace = 0; /* First unused byte of aOvflSpace[] */ - int szScratch; /* Size of scratch memory requested */ + u64 szScratch; /* Size of scratch memory requested */ MemPage *apOld[NB]; /* pPage and up to two siblings */ MemPage *apNew[NB+2]; /* pPage and up to NB siblings after balancing */ u8 *pRight; /* Location in parent of right-sibling pointer */ @@ -80243,7 +81004,7 @@ SQLITE_PRIVATE int sqlite3BtreeInsert( if( pCur->info.nKey==pX->nKey ){ BtreePayload x2; x2.pData = pX->pKey; - x2.nData = pX->nKey; + x2.nData = (int)pX->nKey; assert( pX->nKey<=0x7fffffff ); x2.nZero = 0; return btreeOverwriteCell(pCur, &x2); } @@ -80424,7 +81185,7 @@ SQLITE_PRIVATE int sqlite3BtreeTransferRow(BtCursor *pDest, BtCursor *pSrc, i64 getCellInfo(pSrc); if( pSrc->info.nPayload<0x80 ){ - *(aOut++) = pSrc->info.nPayload; + *(aOut++) = (u8)pSrc->info.nPayload; }else{ aOut += sqlite3PutVarint(aOut, pSrc->info.nPayload); } @@ -80437,7 +81198,7 @@ SQLITE_PRIVATE int sqlite3BtreeTransferRow(BtCursor *pDest, BtCursor *pSrc, i64 nRem = pSrc->info.nPayload; if( nIn==nRem && nInpPage->maxLocal ){ memcpy(aOut, aIn, nIn); - pBt->nPreformatSize = nIn + (aOut - pBt->pTmpSpace); + pBt->nPreformatSize = nIn + (int)(aOut - pBt->pTmpSpace); return SQLITE_OK; }else{ int rc = SQLITE_OK; @@ -80449,7 +81210,7 @@ SQLITE_PRIVATE int sqlite3BtreeTransferRow(BtCursor *pDest, BtCursor *pSrc, i64 u32 nOut; /* Size of output buffer aOut[] */ nOut = btreePayloadToLocal(pDest->pPage, pSrc->info.nPayload); - pBt->nPreformatSize = nOut + (aOut - pBt->pTmpSpace); + pBt->nPreformatSize = (int)nOut + (int)(aOut - pBt->pTmpSpace); if( nOutinfo.nPayload ){ pPgnoOut = &aOut[nOut]; pBt->nPreformatSize += 4; @@ -82070,6 +82831,7 @@ SQLITE_PRIVATE int sqlite3BtreeIsInBackup(Btree *p){ */ SQLITE_PRIVATE void *sqlite3BtreeSchema(Btree *p, int nBytes, void(*xFree)(void *)){ BtShared *pBt = p->pBt; + assert( nBytes==0 || nBytes==sizeof(Schema) ); sqlite3BtreeEnter(p); if( !pBt->pSchema && nBytes ){ pBt->pSchema = sqlite3DbMallocZero(0, nBytes); @@ -83186,7 +83948,7 @@ static void vdbeMemRenderNum(int sz, char *zBuf, Mem *p){ ** corresponding string value, then it is important that the string be ** derived from the numeric value, not the other way around, to ensure ** that the index and table are consistent. See ticket -** https://www.sqlite.org/src/info/343634942dd54ab (2018-01-31) for +** https://sqlite.org/src/info/343634942dd54ab (2018-01-31) for ** an example. ** ** This routine looks at pMem to verify that if it has both a numeric @@ -83372,7 +84134,7 @@ SQLITE_PRIVATE void sqlite3VdbeMemZeroTerminateIfAble(Mem *pMem){ return; } if( pMem->enc!=SQLITE_UTF8 ) return; - if( NEVER(pMem->z==0) ) return; + assert( pMem->z!=0 ); if( pMem->flags & MEM_Dyn ){ if( pMem->xDel==sqlite3_free && sqlite3_msize(pMem->z) >= (u64)(pMem->n+1) @@ -84485,7 +85247,7 @@ static sqlite3_value *valueNew(sqlite3 *db, struct ValueNewStat4Ctx *p){ if( pRec==0 ){ Index *pIdx = p->pIdx; /* Index being probed */ - int nByte; /* Bytes of space to allocate */ + i64 nByte; /* Bytes of space to allocate */ int i; /* Counter variable */ int nCol = pIdx->nColumn; /* Number of index columns including rowid */ @@ -84551,7 +85313,7 @@ static int valueFromFunction( ){ sqlite3_context ctx; /* Context object for function invocation */ sqlite3_value **apVal = 0; /* Function arguments */ - int nVal = 0; /* Size of apVal[] array */ + int nVal = 0; /* Number of function arguments */ FuncDef *pFunc = 0; /* Function definition */ sqlite3_value *pVal = 0; /* New value */ int rc = SQLITE_OK; /* Return code */ @@ -85549,12 +86311,10 @@ SQLITE_PRIVATE int sqlite3VdbeAddFunctionCall( int eCallCtx /* Calling context */ ){ Vdbe *v = pParse->pVdbe; - int nByte; int addr; sqlite3_context *pCtx; assert( v ); - nByte = sizeof(*pCtx) + (nArg-1)*sizeof(sqlite3_value*); - pCtx = sqlite3DbMallocRawNN(pParse->db, nByte); + pCtx = sqlite3DbMallocRawNN(pParse->db, SZ_CONTEXT(nArg)); if( pCtx==0 ){ assert( pParse->db->mallocFailed ); freeEphemeralFunction(pParse->db, (FuncDef*)pFunc); @@ -85830,7 +86590,7 @@ static Op *opIterNext(VdbeOpIter *p){ } if( pRet->p4type==P4_SUBPROGRAM ){ - int nByte = (p->nSub+1)*sizeof(SubProgram*); + i64 nByte = (1+(u64)p->nSub)*sizeof(SubProgram*); int j; for(j=0; jnSub; j++){ if( p->apSub[j]==pRet->p4.pProgram ) break; @@ -85960,8 +86720,8 @@ SQLITE_PRIVATE void sqlite3VdbeAssertAbortable(Vdbe *p){ ** (1) For each jump instruction with a negative P2 value (a label) ** resolve the P2 value to an actual address. ** -** (2) Compute the maximum number of arguments used by any SQL function -** and store that value in *pMaxFuncArgs. +** (2) Compute the maximum number of arguments used by the xUpdate/xFilter +** methods of any virtual table and store that value in *pMaxVtabArgs. ** ** (3) Update the Vdbe.readOnly and Vdbe.bIsReader flags to accurately ** indicate what the prepared statement actually does. @@ -85974,8 +86734,8 @@ SQLITE_PRIVATE void sqlite3VdbeAssertAbortable(Vdbe *p){ ** script numbers the opcodes correctly. Changes to this routine must be ** coordinated with changes to mkopcodeh.tcl. */ -static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){ - int nMaxArgs = *pMaxFuncArgs; +static void resolveP2Values(Vdbe *p, int *pMaxVtabArgs){ + int nMaxVtabArgs = *pMaxVtabArgs; Op *pOp; Parse *pParse = p->pParse; int *aLabel = pParse->aLabel; @@ -86020,15 +86780,19 @@ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){ } #ifndef SQLITE_OMIT_VIRTUALTABLE case OP_VUpdate: { - if( pOp->p2>nMaxArgs ) nMaxArgs = pOp->p2; + if( pOp->p2>nMaxVtabArgs ) nMaxVtabArgs = pOp->p2; break; } case OP_VFilter: { int n; + /* The instruction immediately prior to VFilter will be an + ** OP_Integer that sets the "argc" value for the VFilter. See + ** the code where OP_VFilter is generated at tag-20250207a. */ assert( (pOp - p->aOp) >= 3 ); assert( pOp[-1].opcode==OP_Integer ); + assert( pOp[-1].p2==pOp->p3+1 ); n = pOp[-1].p1; - if( n>nMaxArgs ) nMaxArgs = n; + if( n>nMaxVtabArgs ) nMaxVtabArgs = n; /* Fall through into the default case */ /* no break */ deliberate_fall_through } @@ -86069,7 +86833,7 @@ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){ pParse->aLabel = 0; } pParse->nLabel = 0; - *pMaxFuncArgs = nMaxArgs; + *pMaxVtabArgs = nMaxVtabArgs; assert( p->bIsReader!=0 || DbMaskAllZero(p->btreeMask) ); } @@ -86298,7 +87062,7 @@ SQLITE_PRIVATE void sqlite3VdbeScanStatus( const char *zName /* Name of table or index being scanned */ ){ if( IS_STMT_SCANSTATUS(p->db) ){ - sqlite3_int64 nByte = (p->nScan+1) * sizeof(ScanStatus); + i64 nByte = (1+(i64)p->nScan) * sizeof(ScanStatus); ScanStatus *aNew; aNew = (ScanStatus*)sqlite3DbRealloc(p->db, p->aScan, nByte); if( aNew ){ @@ -86408,6 +87172,9 @@ SQLITE_PRIVATE void sqlite3VdbeChangeP5(Vdbe *p, u16 p5){ */ SQLITE_PRIVATE void sqlite3VdbeTypeofColumn(Vdbe *p, int iDest){ VdbeOp *pOp = sqlite3VdbeGetLastOp(p); +#ifdef SQLITE_DEBUG + while( pOp->opcode==OP_ReleaseReg ) pOp--; +#endif if( pOp->p3==iDest && pOp->opcode==OP_Column ){ pOp->p5 |= OPFLAG_TYPEOFARG; } @@ -87747,7 +88514,7 @@ SQLITE_PRIVATE void sqlite3VdbeMakeReady( int nVar; /* Number of parameters */ int nMem; /* Number of VM memory registers */ int nCursor; /* Number of cursors required */ - int nArg; /* Number of arguments in subprograms */ + int nArg; /* Max number args to xFilter or xUpdate */ int n; /* Loop counter */ struct ReusableSpace x; /* Reusable bulk memory */ @@ -87819,6 +88586,9 @@ SQLITE_PRIVATE void sqlite3VdbeMakeReady( p->apCsr = allocSpace(&x, p->apCsr, nCursor*sizeof(VdbeCursor*)); } } +#ifdef SQLITE_DEBUG + p->napArg = nArg; +#endif if( db->mallocFailed ){ p->nVar = 0; @@ -89316,6 +90086,7 @@ SQLITE_PRIVATE UnpackedRecord *sqlite3VdbeAllocUnpackedRecord( ){ UnpackedRecord *p; /* Unpacked record to return */ int nByte; /* Number of bytes required for *p */ + assert( sizeof(UnpackedRecord) + sizeof(Mem)*65536 < 0x7fffffff ); nByte = ROUND8P(sizeof(UnpackedRecord)) + sizeof(Mem)*(pKeyInfo->nKeyField+1); p = (UnpackedRecord *)sqlite3DbMallocRaw(pKeyInfo->db, nByte); if( !p ) return 0; @@ -90622,10 +91393,11 @@ SQLITE_PRIVATE void sqlite3VdbePreUpdateHook( preupdate.pCsr = pCsr; preupdate.op = op; preupdate.iNewReg = iReg; - preupdate.keyinfo.db = db; - preupdate.keyinfo.enc = ENC(db); - preupdate.keyinfo.nKeyField = pTab->nCol; - preupdate.keyinfo.aSortFlags = (u8*)&fakeSortOrder; + preupdate.pKeyinfo = (KeyInfo*)&preupdate.keyinfoSpace; + preupdate.pKeyinfo->db = db; + preupdate.pKeyinfo->enc = ENC(db); + preupdate.pKeyinfo->nKeyField = pTab->nCol; + preupdate.pKeyinfo->aSortFlags = (u8*)&fakeSortOrder; preupdate.iKey1 = iKey1; preupdate.iKey2 = iKey2; preupdate.pTab = pTab; @@ -90635,8 +91407,8 @@ SQLITE_PRIVATE void sqlite3VdbePreUpdateHook( db->xPreUpdateCallback(db->pPreUpdateArg, db, op, zDb, zTbl, iKey1, iKey2); db->pPreUpdate = 0; sqlite3DbFree(db, preupdate.aRecord); - vdbeFreeUnpacked(db, preupdate.keyinfo.nKeyField+1, preupdate.pUnpacked); - vdbeFreeUnpacked(db, preupdate.keyinfo.nKeyField+1, preupdate.pNewUnpacked); + vdbeFreeUnpacked(db, preupdate.pKeyinfo->nKeyField+1,preupdate.pUnpacked); + vdbeFreeUnpacked(db, preupdate.pKeyinfo->nKeyField+1,preupdate.pNewUnpacked); sqlite3VdbeMemRelease(&preupdate.oldipk); if( preupdate.aNew ){ int i; @@ -92467,7 +93239,7 @@ SQLITE_API int sqlite3_bind_text64( assert( xDel!=SQLITE_DYNAMIC ); if( enc!=SQLITE_UTF8 ){ if( enc==SQLITE_UTF16 ) enc = SQLITE_UTF16NATIVE; - nData &= ~(u16)1; + nData &= ~(u64)1; } return bindText(pStmt, i, zData, nData, xDel, enc); } @@ -92875,7 +93647,7 @@ SQLITE_API int sqlite3_preupdate_old(sqlite3 *db, int iIdx, sqlite3_value **ppVa if( !aRec ) goto preupdate_old_out; rc = sqlite3BtreePayload(p->pCsr->uc.pCursor, 0, nRec, aRec); if( rc==SQLITE_OK ){ - p->pUnpacked = vdbeUnpackRecord(&p->keyinfo, nRec, aRec); + p->pUnpacked = vdbeUnpackRecord(p->pKeyinfo, nRec, aRec); if( !p->pUnpacked ) rc = SQLITE_NOMEM; } if( rc!=SQLITE_OK ){ @@ -92892,7 +93664,9 @@ SQLITE_API int sqlite3_preupdate_old(sqlite3 *db, int iIdx, sqlite3_value **ppVa Column *pCol = &p->pTab->aCol[iIdx]; if( pCol->iDflt>0 ){ if( p->apDflt==0 ){ - int nByte = sizeof(sqlite3_value*)*p->pTab->nCol; + int nByte; + assert( sizeof(sqlite3_value*)*UMXV(p->pTab->nCol) < 0x7fffffff ); + nByte = sizeof(sqlite3_value*)*p->pTab->nCol; p->apDflt = (sqlite3_value**)sqlite3DbMallocZero(db, nByte); if( p->apDflt==0 ) goto preupdate_old_out; } @@ -92938,7 +93712,7 @@ SQLITE_API int sqlite3_preupdate_count(sqlite3 *db){ #else p = db->pPreUpdate; #endif - return (p ? p->keyinfo.nKeyField : 0); + return (p ? p->pKeyinfo->nKeyField : 0); } #endif /* SQLITE_ENABLE_PREUPDATE_HOOK */ @@ -93021,7 +93795,7 @@ SQLITE_API int sqlite3_preupdate_new(sqlite3 *db, int iIdx, sqlite3_value **ppVa Mem *pData = &p->v->aMem[p->iNewReg]; rc = ExpandBlob(pData); if( rc!=SQLITE_OK ) goto preupdate_new_out; - pUnpack = vdbeUnpackRecord(&p->keyinfo, pData->n, pData->z); + pUnpack = vdbeUnpackRecord(p->pKeyinfo, pData->n, pData->z); if( !pUnpack ){ rc = SQLITE_NOMEM; goto preupdate_new_out; @@ -93042,7 +93816,8 @@ SQLITE_API int sqlite3_preupdate_new(sqlite3 *db, int iIdx, sqlite3_value **ppVa */ assert( p->op==SQLITE_UPDATE ); if( !p->aNew ){ - p->aNew = (Mem *)sqlite3DbMallocZero(db, sizeof(Mem) * p->pCsr->nField); + assert( sizeof(Mem)*UMXV(p->pCsr->nField) < 0x7fffffff ); + p->aNew = (Mem *)sqlite3DbMallocZero(db, sizeof(Mem)*p->pCsr->nField); if( !p->aNew ){ rc = SQLITE_NOMEM; goto preupdate_new_out; @@ -93812,11 +94587,11 @@ static VdbeCursor *allocateCursor( */ Mem *pMem = iCur>0 ? &p->aMem[p->nMem-iCur] : p->aMem; - int nByte; + i64 nByte; VdbeCursor *pCx = 0; - nByte = - ROUND8P(sizeof(VdbeCursor)) + 2*sizeof(u32)*nField + - (eCurType==CURTYPE_BTREE?sqlite3BtreeCursorSize():0); + nByte = SZ_VDBECURSOR(nField); + assert( ROUND8(nByte)==nByte ); + if( eCurType==CURTYPE_BTREE ) nByte += sqlite3BtreeCursorSize(); assert( iCur>=0 && iCurnCursor ); if( p->apCsr[iCur] ){ /*OPTIMIZATION-IF-FALSE*/ @@ -93840,7 +94615,7 @@ static VdbeCursor *allocateCursor( pMem->szMalloc = 0; return 0; } - pMem->szMalloc = nByte; + pMem->szMalloc = (int)nByte; } p->apCsr[iCur] = pCx = (VdbeCursor*)pMem->zMalloc; @@ -93849,8 +94624,8 @@ static VdbeCursor *allocateCursor( pCx->nField = nField; pCx->aOffset = &pCx->aType[nField]; if( eCurType==CURTYPE_BTREE ){ - pCx->uc.pCursor = (BtCursor*) - &pMem->z[ROUND8P(sizeof(VdbeCursor))+2*sizeof(u32)*nField]; + assert( ROUND8(SZ_VDBECURSOR(nField))==SZ_VDBECURSOR(nField) ); + pCx->uc.pCursor = (BtCursor*)&pMem->z[SZ_VDBECURSOR(nField)]; sqlite3BtreeCursorZero(pCx->uc.pCursor); } return pCx; @@ -94854,7 +95629,7 @@ case OP_Halt: { sqlite3VdbeError(p, "%s", pOp->p4.z); } pcx = (int)(pOp - aOp); - sqlite3_log(pOp->p1, "abort at %d in [%s]: %s", pcx, p->zSql, p->zErrMsg); + sqlite3_log(pOp->p1, "abort at %d: %s; [%s]", pcx, p->zErrMsg, p->zSql); } rc = sqlite3VdbeHalt(p); assert( rc==SQLITE_BUSY || rc==SQLITE_OK || rc==SQLITE_ERROR ); @@ -96180,7 +96955,7 @@ case OP_BitNot: { /* same as TK_BITNOT, in1, out2 */ break; } -/* Opcode: Once P1 P2 * * * +/* Opcode: Once P1 P2 P3 * * ** ** Fall through to the next instruction the first time this opcode is ** encountered on each invocation of the byte-code program. Jump to P2 @@ -96196,6 +96971,12 @@ case OP_BitNot: { /* same as TK_BITNOT, in1, out2 */ ** whether or not the jump should be taken. The bitmask is necessary ** because the self-altering code trick does not work for recursive ** triggers. +** +** The P3 operand is not used directly by this opcode. However P3 is +** used by the code generator as follows: If this opcode is the start +** of a subroutine and that subroutine uses a Bloom filter, then P3 will +** be the register that holds that Bloom filter. See tag-202407032019 +** in the source code for implementation details. */ case OP_Once: { /* jump */ u32 iAddr; /* Address of this instruction */ @@ -97241,6 +98022,7 @@ case OP_MakeRecord: { zHdr += sqlite3PutVarint(zHdr, serial_type); if( pRec->n ){ assert( pRec->z!=0 ); + assert( pRec->z!=(const char*)sqlite3CtypeMap ); memcpy(zPayload, pRec->z, pRec->n); zPayload += pRec->n; } @@ -99592,7 +100374,7 @@ case OP_RowData: { /* The OP_RowData opcodes always follow OP_NotExists or ** OP_SeekRowid or OP_Rewind/Op_Next with no intervening instructions ** that might invalidate the cursor. - ** If this where not the case, on of the following assert()s + ** If this were not the case, one of the following assert()s ** would fail. Should this ever change (because of changes in the code ** generator) then the fix would be to insert a call to ** sqlite3VdbeCursorMoveto(). @@ -100861,7 +101643,7 @@ case OP_RowSetTest: { /* jump, in1, in3 */ */ case OP_Program: { /* jump0 */ int nMem; /* Number of memory registers for sub-program */ - int nByte; /* Bytes of runtime space required for sub-program */ + i64 nByte; /* Bytes of runtime space required for sub-program */ Mem *pRt; /* Register to allocate runtime space */ Mem *pMem; /* Used to iterate through memory cells */ Mem *pEnd; /* Last memory cell in new array */ @@ -100912,7 +101694,7 @@ case OP_Program: { /* jump0 */ nByte = ROUND8(sizeof(VdbeFrame)) + nMem * sizeof(Mem) + pProgram->nCsr * sizeof(VdbeCursor*) - + (pProgram->nOp + 7)/8; + + (7 + (i64)pProgram->nOp)/8; pFrame = sqlite3DbMallocZero(db, nByte); if( !pFrame ){ goto no_mem; @@ -100920,7 +101702,7 @@ case OP_Program: { /* jump0 */ sqlite3VdbeMemRelease(pRt); pRt->flags = MEM_Blob|MEM_Dyn; pRt->z = (char*)pFrame; - pRt->n = nByte; + pRt->n = (int)nByte; pRt->xDel = sqlite3VdbeFrameMemDel; pFrame->v = p; @@ -101019,12 +101801,14 @@ case OP_Param: { /* out2 */ ** statement counter is incremented (immediate foreign key constraints). */ case OP_FkCounter: { - if( db->flags & SQLITE_DeferFKs ){ - db->nDeferredImmCons += pOp->p2; - }else if( pOp->p1 ){ + if( pOp->p1 ){ db->nDeferredCons += pOp->p2; }else{ - p->nFkConstraint += pOp->p2; + if( db->flags & SQLITE_DeferFKs ){ + db->nDeferredImmCons += pOp->p2; + }else{ + p->nFkConstraint += pOp->p2; + } } break; } @@ -101239,7 +102023,7 @@ case OP_AggStep: { ** ** Note: We could avoid this by using a regular memory cell from aMem[] for ** the accumulator, instead of allocating one here. */ - nAlloc = ROUND8P( sizeof(pCtx[0]) + (n-1)*sizeof(sqlite3_value*) ); + nAlloc = ROUND8P( SZ_CONTEXT(n) ); pCtx = sqlite3DbMallocRawNN(db, nAlloc + sizeof(Mem)); if( pCtx==0 ) goto no_mem; pCtx->pOut = (Mem*)((u8*)pCtx + nAlloc); @@ -101899,6 +102683,7 @@ case OP_VFilter: { /* jump, ncycle */ /* Invoke the xFilter method */ apArg = p->apArg; + assert( nArg<=p->napArg ); for(i = 0; ivtabOnConflict; apArg = p->apArg; pX = &aMem[pOp->p3]; + assert( nArg<=p->napArg ); for(i=0; irc = rc; sqlite3SystemError(db, rc); testcase( sqlite3GlobalConfig.xLog!=0 ); - sqlite3_log(rc, "statement aborts at %d: [%s] %s", - (int)(pOp - aOp), p->zSql, p->zErrMsg); + sqlite3_log(rc, "statement aborts at %d: %s; [%s]", + (int)(pOp - aOp), p->zErrMsg, p->zSql); if( p->eVdbeState==VDBE_RUN_STATE ) sqlite3VdbeHalt(p); if( rc==SQLITE_IOERR_NOMEM ) sqlite3OomFault(db); if( rc==SQLITE_CORRUPT && db->autoCommit==0 ){ @@ -102895,6 +103681,7 @@ SQLITE_API int sqlite3_blob_open( char *zErr = 0; Table *pTab; Incrblob *pBlob = 0; + int iDb; Parse sParse; #ifdef SQLITE_ENABLE_API_ARMOR @@ -102940,7 +103727,10 @@ SQLITE_API int sqlite3_blob_open( sqlite3ErrorMsg(&sParse, "cannot open view: %s", zTable); } #endif - if( !pTab ){ + if( pTab==0 + || ((iDb = sqlite3SchemaToIndex(db, pTab->pSchema))==1 && + sqlite3OpenTempDatabase(&sParse)) + ){ if( sParse.zErrMsg ){ sqlite3DbFree(db, zErr); zErr = sParse.zErrMsg; @@ -102951,15 +103741,11 @@ SQLITE_API int sqlite3_blob_open( goto blob_open_out; } pBlob->pTab = pTab; - pBlob->zDb = db->aDb[sqlite3SchemaToIndex(db, pTab->pSchema)].zDbSName; + pBlob->zDb = db->aDb[iDb].zDbSName; /* Now search pTab for the exact column. */ - for(iCol=0; iColnCol; iCol++) { - if( sqlite3StrICmp(pTab->aCol[iCol].zCnName, zColumn)==0 ){ - break; - } - } - if( iCol==pTab->nCol ){ + iCol = sqlite3ColumnIndex(pTab, zColumn); + if( iCol<0 ){ sqlite3DbFree(db, zErr); zErr = sqlite3MPrintf(db, "no such column: \"%s\"", zColumn); rc = SQLITE_ERROR; @@ -103039,7 +103825,6 @@ SQLITE_API int sqlite3_blob_open( {OP_Halt, 0, 0, 0}, /* 5 */ }; Vdbe *v = (Vdbe *)pBlob->pStmt; - int iDb = sqlite3SchemaToIndex(db, pTab->pSchema); VdbeOp *aOp; sqlite3VdbeAddOp4Int(v, OP_Transaction, iDb, wrFlag, @@ -103617,9 +104402,12 @@ struct VdbeSorter { u8 iPrev; /* Previous thread used to flush PMA */ u8 nTask; /* Size of aTask[] array */ u8 typeMask; - SortSubtask aTask[1]; /* One or more subtasks */ + SortSubtask aTask[FLEXARRAY]; /* One or more subtasks */ }; +/* Size (in bytes) of a VdbeSorter object that works with N or fewer subtasks */ +#define SZ_VDBESORTER(N) (offsetof(VdbeSorter,aTask)+(N)*sizeof(SortSubtask)) + #define SORTER_TYPE_INTEGER 0x01 #define SORTER_TYPE_TEXT 0x02 @@ -104221,7 +105009,7 @@ SQLITE_PRIVATE int sqlite3VdbeSorterInit( VdbeSorter *pSorter; /* The new sorter */ KeyInfo *pKeyInfo; /* Copy of pCsr->pKeyInfo with db==0 */ int szKeyInfo; /* Size of pCsr->pKeyInfo in bytes */ - int sz; /* Size of pSorter in bytes */ + i64 sz; /* Size of pSorter in bytes */ int rc = SQLITE_OK; #if SQLITE_MAX_WORKER_THREADS==0 # define nWorker 0 @@ -104249,8 +105037,10 @@ SQLITE_PRIVATE int sqlite3VdbeSorterInit( assert( pCsr->pKeyInfo ); assert( !pCsr->isEphemeral ); assert( pCsr->eCurType==CURTYPE_SORTER ); - szKeyInfo = sizeof(KeyInfo) + (pCsr->pKeyInfo->nKeyField-1)*sizeof(CollSeq*); - sz = sizeof(VdbeSorter) + nWorker * sizeof(SortSubtask); + assert( sizeof(KeyInfo) + UMXV(pCsr->pKeyInfo->nKeyField)*sizeof(CollSeq*) + < 0x7fffffff ); + szKeyInfo = SZ_KEYINFO(pCsr->pKeyInfo->nKeyField+1); + sz = SZ_VDBESORTER(nWorker+1); pSorter = (VdbeSorter*)sqlite3DbMallocZero(db, sz + szKeyInfo); pCsr->uc.pSorter = pSorter; @@ -104462,7 +105252,7 @@ static int vdbeSorterJoinAll(VdbeSorter *pSorter, int rcin){ */ static MergeEngine *vdbeMergeEngineNew(int nReader){ int N = 2; /* Smallest power of two >= nReader */ - int nByte; /* Total bytes of space to allocate */ + i64 nByte; /* Total bytes of space to allocate */ MergeEngine *pNew; /* Pointer to allocated object to return */ assert( nReader<=SORTER_MAX_MERGE_COUNT ); @@ -104714,6 +105504,10 @@ static int vdbeSorterSort(SortSubtask *pTask, SorterList *pList){ p->u.pNext = 0; for(i=0; aSlot[i]; i++){ p = vdbeSorterMerge(pTask, p, aSlot[i]); + /* ,--Each aSlot[] holds twice as much as the previous. So we cannot use + ** | up all 64 aSlots[] with only a 64-bit address space. + ** v */ + assert( iop on success */ Table *pTab = 0; /* Table holding the row */ - Column *pCol; /* A column of pTab */ ExprList *pFJMatch = 0; /* Matches for FULL JOIN .. USING */ const char *zCol = pRight->u.zToken; @@ -107556,7 +108349,6 @@ static int lookupName( if( pSrcList ){ for(i=0, pItem=pSrcList->a; inSrc; i++, pItem++){ - u8 hCol; pTab = pItem->pSTab; assert( pTab!=0 && pTab->zName!=0 ); assert( pTab->nCol>0 || pParse->nErr ); @@ -107644,43 +108436,38 @@ static int lookupName( sqlite3RenameTokenRemap(pParse, 0, (void*)&pExpr->y.pTab); } } - hCol = sqlite3StrIHash(zCol); - for(j=0, pCol=pTab->aCol; jnCol; j++, pCol++){ - if( pCol->hName==hCol - && sqlite3StrICmp(pCol->zCnName, zCol)==0 - ){ - if( cnt>0 ){ - if( pItem->fg.isUsing==0 - || sqlite3IdListIndex(pItem->u3.pUsing, zCol)<0 - ){ - /* Two or more tables have the same column name which is - ** not joined by USING. This is an error. Signal as much - ** by clearing pFJMatch and letting cnt go above 1. */ - sqlite3ExprListDelete(db, pFJMatch); - pFJMatch = 0; - }else - if( (pItem->fg.jointype & JT_RIGHT)==0 ){ - /* An INNER or LEFT JOIN. Use the left-most table */ - continue; - }else - if( (pItem->fg.jointype & JT_LEFT)==0 ){ - /* A RIGHT JOIN. Use the right-most table */ - cnt = 0; - sqlite3ExprListDelete(db, pFJMatch); - pFJMatch = 0; - }else{ - /* For a FULL JOIN, we must construct a coalesce() func */ - extendFJMatch(pParse, &pFJMatch, pMatch, pExpr->iColumn); - } - } - cnt++; - pMatch = pItem; - /* Substitute the rowid (column -1) for the INTEGER PRIMARY KEY */ - pExpr->iColumn = j==pTab->iPKey ? -1 : (i16)j; - if( pItem->fg.isNestedFrom ){ - sqlite3SrcItemColumnUsed(pItem, j); + j = sqlite3ColumnIndex(pTab, zCol); + if( j>=0 ){ + if( cnt>0 ){ + if( pItem->fg.isUsing==0 + || sqlite3IdListIndex(pItem->u3.pUsing, zCol)<0 + ){ + /* Two or more tables have the same column name which is + ** not joined by USING. This is an error. Signal as much + ** by clearing pFJMatch and letting cnt go above 1. */ + sqlite3ExprListDelete(db, pFJMatch); + pFJMatch = 0; + }else + if( (pItem->fg.jointype & JT_RIGHT)==0 ){ + /* An INNER or LEFT JOIN. Use the left-most table */ + continue; + }else + if( (pItem->fg.jointype & JT_LEFT)==0 ){ + /* A RIGHT JOIN. Use the right-most table */ + cnt = 0; + sqlite3ExprListDelete(db, pFJMatch); + pFJMatch = 0; + }else{ + /* For a FULL JOIN, we must construct a coalesce() func */ + extendFJMatch(pParse, &pFJMatch, pMatch, pExpr->iColumn); } - break; + } + cnt++; + pMatch = pItem; + /* Substitute the rowid (column -1) for the INTEGER PRIMARY KEY */ + pExpr->iColumn = j==pTab->iPKey ? -1 : (i16)j; + if( pItem->fg.isNestedFrom ){ + sqlite3SrcItemColumnUsed(pItem, j); } } if( 0==cnt && VisibleRowid(pTab) ){ @@ -107770,23 +108557,18 @@ static int lookupName( if( pTab ){ int iCol; - u8 hCol = sqlite3StrIHash(zCol); pSchema = pTab->pSchema; cntTab++; - for(iCol=0, pCol=pTab->aCol; iColnCol; iCol++, pCol++){ - if( pCol->hName==hCol - && sqlite3StrICmp(pCol->zCnName, zCol)==0 - ){ - if( iCol==pTab->iPKey ){ - iCol = -1; - } - break; + iCol = sqlite3ColumnIndex(pTab, zCol); + if( iCol>=0 ){ + if( pTab->iPKey==iCol ) iCol = -1; + }else{ + if( sqlite3IsRowid(zCol) && VisibleRowid(pTab) ){ + iCol = -1; + }else{ + iCol = pTab->nCol; } } - if( iCol>=pTab->nCol && sqlite3IsRowid(zCol) && VisibleRowid(pTab) ){ - /* IMP: R-51414-32910 */ - iCol = -1; - } if( iColnCol ){ cnt++; pMatch = 0; @@ -108425,13 +109207,12 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ ** sqlite_version() that might change over time cannot be used ** in an index or generated column. Curiously, they can be used ** in a CHECK constraint. SQLServer, MySQL, and PostgreSQL all - ** all this. */ + ** allow this. */ sqlite3ResolveNotValid(pParse, pNC, "non-deterministic functions", NC_IdxExpr|NC_PartIdx|NC_GenCol, 0, pExpr); }else{ assert( (NC_SelfRef & 0xff)==NC_SelfRef ); /* Must fit in 8 bits */ pExpr->op2 = pNC->ncFlags & NC_SelfRef; - if( pNC->ncFlags & NC_FromDDL ) ExprSetProperty(pExpr, EP_FromDDL); } if( (pDef->funcFlags & SQLITE_FUNC_INTERNAL)!=0 && pParse->nested==0 @@ -108447,6 +109228,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ if( (pDef->funcFlags & (SQLITE_FUNC_DIRECT|SQLITE_FUNC_UNSAFE))!=0 && !IN_RENAME_OBJECT ){ + if( pNC->ncFlags & NC_FromDDL ) ExprSetProperty(pExpr, EP_FromDDL); sqlite3ExprFunctionUsable(pParse, pExpr, pDef); } } @@ -109500,20 +110282,22 @@ SQLITE_PRIVATE int sqlite3ResolveSelfReference( Expr *pExpr, /* Expression to resolve. May be NULL. */ ExprList *pList /* Expression list to resolve. May be NULL. */ ){ - SrcList sSrc; /* Fake SrcList for pParse->pNewTable */ + SrcList *pSrc; /* Fake SrcList for pParse->pNewTable */ NameContext sNC; /* Name context for pParse->pNewTable */ int rc; + u8 srcSpace[SZ_SRCLIST_1]; /* Memory space for the fake SrcList */ assert( type==0 || pTab!=0 ); assert( type==NC_IsCheck || type==NC_PartIdx || type==NC_IdxExpr || type==NC_GenCol || pTab==0 ); memset(&sNC, 0, sizeof(sNC)); - memset(&sSrc, 0, sizeof(sSrc)); + pSrc = (SrcList*)srcSpace; + memset(pSrc, 0, SZ_SRCLIST_1); if( pTab ){ - sSrc.nSrc = 1; - sSrc.a[0].zName = pTab->zName; - sSrc.a[0].pSTab = pTab; - sSrc.a[0].iCursor = -1; + pSrc->nSrc = 1; + pSrc->a[0].zName = pTab->zName; + pSrc->a[0].pSTab = pTab; + pSrc->a[0].iCursor = -1; if( pTab->pSchema!=pParse->db->aDb[1].pSchema ){ /* Cause EP_FromDDL to be set on TK_FUNCTION nodes of non-TEMP ** schema elements */ @@ -109521,7 +110305,7 @@ SQLITE_PRIVATE int sqlite3ResolveSelfReference( } } sNC.pParse = pParse; - sNC.pSrcList = &sSrc; + sNC.pSrcList = pSrc; sNC.ncFlags = type | NC_IsDDL; if( (rc = sqlite3ResolveExprNames(&sNC, pExpr))!=SQLITE_OK ) return rc; if( pList ) rc = sqlite3ResolveExprListNames(&sNC, pList); @@ -111270,7 +112054,7 @@ static Expr *exprDup( SQLITE_PRIVATE With *sqlite3WithDup(sqlite3 *db, With *p){ With *pRet = 0; if( p ){ - sqlite3_int64 nByte = sizeof(*p) + sizeof(p->a[0]) * (p->nCte-1); + sqlite3_int64 nByte = SZ_WITH(p->nCte); pRet = sqlite3DbMallocZero(db, nByte); if( pRet ){ int i; @@ -111381,7 +112165,6 @@ SQLITE_PRIVATE ExprList *sqlite3ExprListDup(sqlite3 *db, const ExprList *p, int } pItem->zEName = sqlite3DbStrDup(db, pOldItem->zEName); pItem->fg = pOldItem->fg; - pItem->fg.done = 0; pItem->u = pOldItem->u; } return pNew; @@ -111398,11 +112181,9 @@ SQLITE_PRIVATE ExprList *sqlite3ExprListDup(sqlite3 *db, const ExprList *p, int SQLITE_PRIVATE SrcList *sqlite3SrcListDup(sqlite3 *db, const SrcList *p, int flags){ SrcList *pNew; int i; - int nByte; assert( db!=0 ); if( p==0 ) return 0; - nByte = sizeof(*p) + (p->nSrc>0 ? sizeof(p->a[0]) * (p->nSrc-1) : 0); - pNew = sqlite3DbMallocRawNN(db, nByte ); + pNew = sqlite3DbMallocRawNN(db, SZ_SRCLIST(p->nSrc) ); if( pNew==0 ) return 0; pNew->nSrc = pNew->nAlloc = p->nSrc; for(i=0; inSrc; i++){ @@ -111464,7 +112245,7 @@ SQLITE_PRIVATE IdList *sqlite3IdListDup(sqlite3 *db, const IdList *p){ int i; assert( db!=0 ); if( p==0 ) return 0; - pNew = sqlite3DbMallocRawNN(db, sizeof(*pNew)+(p->nId-1)*sizeof(p->a[0]) ); + pNew = sqlite3DbMallocRawNN(db, SZ_IDLIST(p->nId)); if( pNew==0 ) return 0; pNew->nId = p->nId; for(i=0; inId; i++){ @@ -111496,7 +112277,7 @@ SQLITE_PRIVATE Select *sqlite3SelectDup(sqlite3 *db, const Select *pDup, int fla pNew->pLimit = sqlite3ExprDup(db, p->pLimit, flags); pNew->iLimit = 0; pNew->iOffset = 0; - pNew->selFlags = p->selFlags & ~SF_UsesEphemeral; + pNew->selFlags = p->selFlags & ~(u32)SF_UsesEphemeral; pNew->addrOpenEphm[0] = -1; pNew->addrOpenEphm[1] = -1; pNew->nSelectRow = p->nSelectRow; @@ -111548,7 +112329,7 @@ SQLITE_PRIVATE SQLITE_NOINLINE ExprList *sqlite3ExprListAppendNew( struct ExprList_item *pItem; ExprList *pList; - pList = sqlite3DbMallocRawNN(db, sizeof(ExprList)+sizeof(pList->a[0])*4 ); + pList = sqlite3DbMallocRawNN(db, SZ_EXPRLIST(4)); if( pList==0 ){ sqlite3ExprDelete(db, pExpr); return 0; @@ -111568,8 +112349,7 @@ SQLITE_PRIVATE SQLITE_NOINLINE ExprList *sqlite3ExprListAppendGrow( struct ExprList_item *pItem; ExprList *pNew; pList->nAlloc *= 2; - pNew = sqlite3DbRealloc(db, pList, - sizeof(*pList)+(pList->nAlloc-1)*sizeof(pList->a[0])); + pNew = sqlite3DbRealloc(db, pList, SZ_EXPRLIST(pList->nAlloc)); if( pNew==0 ){ sqlite3ExprListDelete(db, pList); sqlite3ExprDelete(db, pExpr); @@ -112498,13 +113278,7 @@ SQLITE_PRIVATE const char *sqlite3RowidAlias(Table *pTab){ int ii; assert( VisibleRowid(pTab) ); for(ii=0; iinCol; iCol++){ - if( sqlite3_stricmp(azOpt[ii], pTab->aCol[iCol].zCnName)==0 ) break; - } - if( iCol==pTab->nCol ){ - return azOpt[ii]; - } + if( sqlite3ColumnIndex(pTab, azOpt[ii])<0 ) return azOpt[ii]; } return 0; } @@ -112908,7 +113682,7 @@ static char *exprINAffinity(Parse *pParse, const Expr *pExpr){ char *zRet; assert( pExpr->op==TK_IN ); - zRet = sqlite3DbMallocRaw(pParse->db, nVal+1); + zRet = sqlite3DbMallocRaw(pParse->db, 1+(i64)nVal); if( zRet ){ int i; for(i=0; idb, pCopy); sqlite3DbFree(pParse->db, dest.zAffSdst); if( addrBloom ){ + /* Remember that location of the Bloom filter in the P3 operand + ** of the OP_Once that began this subroutine. tag-202407032019 */ sqlite3VdbeGetOp(v, addrOnce)->p3 = dest.iSDParm2; if( dest.iSDParm2==0 ){ - sqlite3VdbeChangeToNoop(v, addrBloom); - }else{ - sqlite3VdbeGetOp(v, addrOnce)->p3 = dest.iSDParm2; + /* If the Bloom filter won't actually be used, keep it small */ + sqlite3VdbeGetOp(v, addrBloom)->p1 = 10; } } if( rc ){ @@ -113619,7 +114394,7 @@ static void sqlite3ExprCodeIN( if( ExprHasProperty(pExpr, EP_Subrtn) ){ const VdbeOp *pOp = sqlite3VdbeGetOp(v, pExpr->y.sub.iAddr); assert( pOp->opcode==OP_Once || pParse->nErr ); - if( pOp->opcode==OP_Once && pOp->p3>0 ){ + if( pOp->opcode==OP_Once && pOp->p3>0 ){ /* tag-202407032019 */ assert( OptimizationEnabled(pParse->db, SQLITE_BloomFilter) ); sqlite3VdbeAddOp4Int(v, OP_Filter, pOp->p3, destIfFalse, rLhs, nVector); VdbeCoverage(v); @@ -114211,7 +114986,7 @@ static SQLITE_NOINLINE int sqlite3IndexedExprLookup( /* -** Expresion pExpr is guaranteed to be a TK_COLUMN or equivalent. This +** Expression pExpr is guaranteed to be a TK_COLUMN or equivalent. This ** function checks the Parse.pIdxPartExpr list to see if this column ** can be replaced with a constant value. If so, it generates code to ** put the constant value in a register (ideally, but not necessarily, @@ -115468,11 +116243,11 @@ SQLITE_PRIVATE void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int assert( TK_ISNULL==OP_IsNull ); testcase( op==TK_ISNULL ); assert( TK_NOTNULL==OP_NotNull ); testcase( op==TK_NOTNULL ); r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1); - sqlite3VdbeTypeofColumn(v, r1); + assert( regFree1==0 || regFree1==r1 ); + if( regFree1 ) sqlite3VdbeTypeofColumn(v, r1); sqlite3VdbeAddOp2(v, op, r1, dest); VdbeCoverageIf(v, op==TK_ISNULL); VdbeCoverageIf(v, op==TK_NOTNULL); - testcase( regFree1==0 ); break; } case TK_BETWEEN: { @@ -115643,11 +116418,11 @@ SQLITE_PRIVATE void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int case TK_ISNULL: case TK_NOTNULL: { r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1); - sqlite3VdbeTypeofColumn(v, r1); + assert( regFree1==0 || regFree1==r1 ); + if( regFree1 ) sqlite3VdbeTypeofColumn(v, r1); sqlite3VdbeAddOp2(v, op, r1, dest); testcase( op==TK_ISNULL ); VdbeCoverageIf(v, op==TK_ISNULL); testcase( op==TK_NOTNULL ); VdbeCoverageIf(v, op==TK_NOTNULL); - testcase( regFree1==0 ); break; } case TK_BETWEEN: { @@ -117452,13 +118227,13 @@ SQLITE_PRIVATE void sqlite3AlterBeginAddColumn(Parse *pParse, SrcList *pSrc){ assert( pNew->nCol>0 ); nAlloc = (((pNew->nCol-1)/8)*8)+8; assert( nAlloc>=pNew->nCol && nAlloc%8==0 && nAlloc-pNew->nCol<8 ); - pNew->aCol = (Column*)sqlite3DbMallocZero(db, sizeof(Column)*nAlloc); + pNew->aCol = (Column*)sqlite3DbMallocZero(db, sizeof(Column)*(u32)nAlloc); pNew->zName = sqlite3MPrintf(db, "sqlite_altertab_%s", pTab->zName); if( !pNew->aCol || !pNew->zName ){ assert( db->mallocFailed ); goto exit_begin_add_column; } - memcpy(pNew->aCol, pTab->aCol, sizeof(Column)*pNew->nCol); + memcpy(pNew->aCol, pTab->aCol, sizeof(Column)*(size_t)pNew->nCol); for(i=0; inCol; i++){ Column *pCol = &pNew->aCol[i]; pCol->zCnName = sqlite3DbStrDup(db, pCol->zCnName); @@ -117553,10 +118328,8 @@ SQLITE_PRIVATE void sqlite3AlterRenameColumn( ** altered. Set iCol to be the index of the column being renamed */ zOld = sqlite3NameFromToken(db, pOld); if( !zOld ) goto exit_rename_column; - for(iCol=0; iColnCol; iCol++){ - if( 0==sqlite3StrICmp(pTab->aCol[iCol].zCnName, zOld) ) break; - } - if( iCol==pTab->nCol ){ + iCol = sqlite3ColumnIndex(pTab, zOld); + if( iCol<0 ){ sqlite3ErrorMsg(pParse, "no such column: \"%T\"", pOld); goto exit_rename_column; } @@ -118059,6 +118832,7 @@ static int renameParseSql( int bTemp /* True if SQL is from temp schema */ ){ int rc; + u64 flags; sqlite3ParseObjectInit(p, db); if( zSql==0 ){ @@ -118067,11 +118841,21 @@ static int renameParseSql( if( sqlite3StrNICmp(zSql,"CREATE ",7)!=0 ){ return SQLITE_CORRUPT_BKPT; } - db->init.iDb = bTemp ? 1 : sqlite3FindDbName(db, zDb); + if( bTemp ){ + db->init.iDb = 1; + }else{ + int iDb = sqlite3FindDbName(db, zDb); + assert( iDb>=0 && iDb<=0xff ); + db->init.iDb = (u8)iDb; + } p->eParseMode = PARSE_MODE_RENAME; p->db = db; p->nQueryLoop = 1; + flags = db->flags; + testcase( (db->flags & SQLITE_Comments)==0 && strstr(zSql," /* ")!=0 ); + db->flags |= SQLITE_Comments; rc = sqlite3RunParser(p, zSql); + db->flags = flags; if( db->mallocFailed ) rc = SQLITE_NOMEM; if( rc==SQLITE_OK && NEVER(p->pNewTable==0 && p->pNewIndex==0 && p->pNewTrigger==0) @@ -118134,10 +118918,11 @@ static int renameEditSql( nQuot = sqlite3Strlen30(zQuot)-1; } - assert( nQuot>=nNew ); - zOut = sqlite3DbMallocZero(db, nSql + pRename->nList*nQuot + 1); + assert( nQuot>=nNew && nSql>=0 && nNew>=0 ); + zOut = sqlite3DbMallocZero(db, (u64)nSql + pRename->nList*(u64)nQuot + 1); }else{ - zOut = (char*)sqlite3DbMallocZero(db, (nSql*2+1) * 3); + assert( nSql>0 ); + zOut = (char*)sqlite3DbMallocZero(db, (2*(u64)nSql + 1) * 3); if( zOut ){ zBuf1 = &zOut[nSql*2+1]; zBuf2 = &zOut[nSql*4+2]; @@ -118149,16 +118934,17 @@ static int renameEditSql( ** with the new column name, or with single-quoted versions of themselves. ** All that remains is to construct and return the edited SQL string. */ if( zOut ){ - int nOut = nSql; - memcpy(zOut, zSql, nSql); + i64 nOut = nSql; + assert( nSql>0 ); + memcpy(zOut, zSql, (size_t)nSql); while( pRename->pList ){ int iOff; /* Offset of token to replace in zOut */ - u32 nReplace; + i64 nReplace; const char *zReplace; RenameToken *pBest = renameColumnTokenNext(pRename); if( zNew ){ - if( bQuote==0 && sqlite3IsIdChar(*pBest->t.z) ){ + if( bQuote==0 && sqlite3IsIdChar(*(u8*)pBest->t.z) ){ nReplace = nNew; zReplace = zNew; }else{ @@ -118176,14 +118962,15 @@ static int renameEditSql( memcpy(zBuf1, pBest->t.z, pBest->t.n); zBuf1[pBest->t.n] = 0; sqlite3Dequote(zBuf1); - sqlite3_snprintf(nSql*2, zBuf2, "%Q%s", zBuf1, + assert( nSql < 0x15555554 /* otherwise malloc would have failed */ ); + sqlite3_snprintf((int)(nSql*2), zBuf2, "%Q%s", zBuf1, pBest->t.z[pBest->t.n]=='\'' ? " " : "" ); zReplace = zBuf2; nReplace = sqlite3Strlen30(zReplace); } - iOff = pBest->t.z - zSql; + iOff = (int)(pBest->t.z - zSql); if( pBest->t.n!=nReplace ){ memmove(&zOut[iOff + nReplace], &zOut[iOff + pBest->t.n], nOut - (iOff + pBest->t.n) @@ -118209,11 +118996,12 @@ static int renameEditSql( ** Set all pEList->a[].fg.eEName fields in the expression-list to val. */ static void renameSetENames(ExprList *pEList, int val){ + assert( val==ENAME_NAME || val==ENAME_TAB || val==ENAME_SPAN ); if( pEList ){ int i; for(i=0; inExpr; i++){ assert( val==ENAME_NAME || pEList->a[i].fg.eEName==ENAME_NAME ); - pEList->a[i].fg.eEName = val; + pEList->a[i].fg.eEName = val&0x3; } } } @@ -118470,7 +119258,7 @@ static void renameColumnFunc( if( sParse.pNewTable ){ if( IsView(sParse.pNewTable) ){ Select *pSelect = sParse.pNewTable->u.view.pSelect; - pSelect->selFlags &= ~SF_View; + pSelect->selFlags &= ~(u32)SF_View; sParse.rc = SQLITE_OK; sqlite3SelectPrep(&sParse, pSelect, 0); rc = (db->mallocFailed ? SQLITE_NOMEM : sParse.rc); @@ -118688,7 +119476,7 @@ static void renameTableFunc( sNC.pParse = &sParse; assert( pSelect->selFlags & SF_View ); - pSelect->selFlags &= ~SF_View; + pSelect->selFlags &= ~(u32)SF_View; sqlite3SelectPrep(&sParse, pTab->u.view.pSelect, &sNC); if( sParse.nErr ){ rc = sParse.rc; @@ -118861,7 +119649,7 @@ static void renameQuotefixFunc( if( sParse.pNewTable ){ if( IsView(sParse.pNewTable) ){ Select *pSelect = sParse.pNewTable->u.view.pSelect; - pSelect->selFlags &= ~SF_View; + pSelect->selFlags &= ~(u32)SF_View; sParse.rc = SQLITE_OK; sqlite3SelectPrep(&sParse, pSelect, 0); rc = (db->mallocFailed ? SQLITE_NOMEM : sParse.rc); @@ -118960,10 +119748,10 @@ static void renameTableTest( if( zDb && zInput ){ int rc; Parse sParse; - int flags = db->flags; + u64 flags = db->flags; if( bNoDQS ) db->flags &= ~(SQLITE_DqsDML|SQLITE_DqsDDL); rc = renameParseSql(&sParse, zDb, db, zInput, bTemp); - db->flags |= (flags & (SQLITE_DqsDML|SQLITE_DqsDDL)); + db->flags = flags; if( rc==SQLITE_OK ){ if( isLegacy==0 && sParse.pNewTable && IsView(sParse.pNewTable) ){ NameContext sNC; @@ -119455,7 +120243,8 @@ static void openStatTable( sqlite3NestedParse(pParse, "CREATE TABLE %Q.%s(%s)", pDb->zDbSName, zTab, aTable[i].zCols ); - aRoot[i] = (u32)pParse->regRoot; + assert( pParse->isCreate || pParse->nErr ); + aRoot[i] = (u32)pParse->u1.cr.regRoot; aCreateTbl[i] = OPFLAG_P2ISREG; } }else{ @@ -119646,7 +120435,7 @@ static void statInit( int nCol; /* Number of columns in index being sampled */ int nKeyCol; /* Number of key columns */ int nColUp; /* nCol rounded up for alignment */ - int n; /* Bytes of space to allocate */ + i64 n; /* Bytes of space to allocate */ sqlite3 *db = sqlite3_context_db_handle(context); /* Database connection */ #ifdef SQLITE_ENABLE_STAT4 /* Maximum number of samples. 0 if STAT4 data is not collected */ @@ -119682,7 +120471,7 @@ static void statInit( p->db = db; p->nEst = sqlite3_value_int64(argv[2]); p->nRow = 0; - p->nLimit = sqlite3_value_int64(argv[3]); + p->nLimit = sqlite3_value_int(argv[3]); p->nCol = nCol; p->nKeyCol = nKeyCol; p->nSkipAhead = 0; @@ -120815,16 +121604,6 @@ static void decodeIntArray( while( z[0]!=0 && z[0]!=' ' ) z++; while( z[0]==' ' ) z++; } - - /* Set the bLowQual flag if the peak number of rows obtained - ** from a full equality match is so large that a full table scan - ** seems likely to be faster than using the index. - */ - if( aLog[0] > 66 /* Index has more than 100 rows */ - && aLog[0] <= aLog[nOut-1] /* And only a single value seen */ - ){ - pIndex->bLowQual = 1; - } } } @@ -121420,7 +122199,7 @@ static void attachFunc( if( aNew==0 ) return; memcpy(aNew, db->aDb, sizeof(db->aDb[0])*2); }else{ - aNew = sqlite3DbRealloc(db, db->aDb, sizeof(db->aDb[0])*(db->nDb+1) ); + aNew = sqlite3DbRealloc(db, db->aDb, sizeof(db->aDb[0])*(1+(i64)db->nDb)); if( aNew==0 ) return; } db->aDb = aNew; @@ -121491,6 +122270,13 @@ static void attachFunc( sqlite3BtreeEnterAll(db); db->init.iDb = 0; db->mDbFlags &= ~(DBFLAG_SchemaKnownOk); +#ifdef SQLITE_ENABLE_SETLK_TIMEOUT + if( db->setlkFlags & SQLITE_SETLK_BLOCK_ON_CONNECT ){ + int val = 1; + sqlite3_file *fd = sqlite3PagerFile(sqlite3BtreePager(pNew->pBt)); + sqlite3OsFileControlHint(fd, SQLITE_FCNTL_BLOCK_ON_CONNECT, &val); + } +#endif if( !REOPEN_AS_MEMDB(db) ){ rc = sqlite3Init(db, &zErrDyn); } @@ -122213,6 +122999,7 @@ static SQLITE_NOINLINE void lockTable( } } + assert( pToplevel->nTableLock < 0x7fff0000 ); nBytes = sizeof(TableLock) * (pToplevel->nTableLock+1); pToplevel->aTableLock = sqlite3DbReallocOrFree(pToplevel->db, pToplevel->aTableLock, nBytes); @@ -122313,10 +123100,12 @@ SQLITE_PRIVATE void sqlite3FinishCoding(Parse *pParse){ || sqlite3VdbeAssertMayAbort(v, pParse->mayAbort)); if( v ){ if( pParse->bReturning ){ - Returning *pReturning = pParse->u1.pReturning; + Returning *pReturning; int addrRewind; int reg; + assert( !pParse->isCreate ); + pReturning = pParse->u1.d.pReturning; if( pReturning->nRetCol ){ sqlite3VdbeAddOp0(v, OP_FkCheck); addrRewind = @@ -122392,7 +123181,9 @@ SQLITE_PRIVATE void sqlite3FinishCoding(Parse *pParse){ } if( pParse->bReturning ){ - Returning *pRet = pParse->u1.pReturning; + Returning *pRet; + assert( !pParse->isCreate ); + pRet = pParse->u1.d.pReturning; if( pRet->nRetCol ){ sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pRet->iRetCur, pRet->nRetCol); } @@ -123207,10 +123998,16 @@ SQLITE_PRIVATE Index *sqlite3PrimaryKeyIndex(Table *pTab){ ** find the (first) offset of that column in index pIdx. Or return -1 ** if column iCol is not used in index pIdx. */ -SQLITE_PRIVATE i16 sqlite3TableColumnToIndex(Index *pIdx, i16 iCol){ +SQLITE_PRIVATE int sqlite3TableColumnToIndex(Index *pIdx, int iCol){ int i; + i16 iCol16; + assert( iCol>=(-1) && iCol<=SQLITE_MAX_COLUMN ); + assert( pIdx->nColumn<=SQLITE_MAX_COLUMN+1 ); + iCol16 = iCol; for(i=0; inColumn; i++){ - if( iCol==pIdx->aiColumn[i] ) return i; + if( iCol16==pIdx->aiColumn[i] ){ + return i; + } } return -1; } @@ -123464,8 +124261,9 @@ SQLITE_PRIVATE void sqlite3StartTable( /* If the file format and encoding in the database have not been set, ** set them now. */ - reg1 = pParse->regRowid = ++pParse->nMem; - reg2 = pParse->regRoot = ++pParse->nMem; + assert( pParse->isCreate ); + reg1 = pParse->u1.cr.regRowid = ++pParse->nMem; + reg2 = pParse->u1.cr.regRoot = ++pParse->nMem; reg3 = ++pParse->nMem; sqlite3VdbeAddOp3(v, OP_ReadCookie, iDb, reg3, BTREE_FILE_FORMAT); sqlite3VdbeUsesBtree(v, iDb); @@ -123480,8 +124278,8 @@ SQLITE_PRIVATE void sqlite3StartTable( ** The record created does not contain anything yet. It will be replaced ** by the real entry in code generated at sqlite3EndTable(). ** - ** The rowid for the new entry is left in register pParse->regRowid. - ** The root page number of the new table is left in reg pParse->regRoot. + ** The rowid for the new entry is left in register pParse->u1.cr.regRowid. + ** The root page of the new table is left in reg pParse->u1.cr.regRoot. ** The rowid and root page number values are needed by the code that ** sqlite3EndTable will generate. */ @@ -123492,7 +124290,7 @@ SQLITE_PRIVATE void sqlite3StartTable( #endif { assert( !pParse->bReturning ); - pParse->u1.addrCrTab = + pParse->u1.cr.addrCrTab = sqlite3VdbeAddOp3(v, OP_CreateBtree, iDb, reg2, BTREE_INTKEY); } sqlite3OpenSchemaTable(pParse, iDb); @@ -123570,7 +124368,8 @@ SQLITE_PRIVATE void sqlite3AddReturning(Parse *pParse, ExprList *pList){ sqlite3ExprListDelete(db, pList); return; } - pParse->u1.pReturning = pRet; + assert( !pParse->isCreate ); + pParse->u1.d.pReturning = pRet; pRet->pParse = pParse; pRet->pReturnEL = pList; sqlite3ParserAddCleanup(pParse, sqlite3DeleteReturning, pRet); @@ -123612,7 +124411,6 @@ SQLITE_PRIVATE void sqlite3AddColumn(Parse *pParse, Token sName, Token sType){ char *zType; Column *pCol; sqlite3 *db = pParse->db; - u8 hName; Column *aNew; u8 eType = COLTYPE_CUSTOM; u8 szEst = 1; @@ -123666,13 +124464,10 @@ SQLITE_PRIVATE void sqlite3AddColumn(Parse *pParse, Token sName, Token sType){ memcpy(z, sName.z, sName.n); z[sName.n] = 0; sqlite3Dequote(z); - hName = sqlite3StrIHash(z); - for(i=0; inCol; i++){ - if( p->aCol[i].hName==hName && sqlite3StrICmp(z, p->aCol[i].zCnName)==0 ){ - sqlite3ErrorMsg(pParse, "duplicate column name: %s", z); - sqlite3DbFree(db, z); - return; - } + if( p->nCol && sqlite3ColumnIndex(p, z)>=0 ){ + sqlite3ErrorMsg(pParse, "duplicate column name: %s", z); + sqlite3DbFree(db, z); + return; } aNew = sqlite3DbRealloc(db,p->aCol,((i64)p->nCol+1)*sizeof(p->aCol[0])); if( aNew==0 ){ @@ -123683,7 +124478,7 @@ SQLITE_PRIVATE void sqlite3AddColumn(Parse *pParse, Token sName, Token sType){ pCol = &p->aCol[p->nCol]; memset(pCol, 0, sizeof(p->aCol[0])); pCol->zCnName = z; - pCol->hName = hName; + pCol->hName = sqlite3StrIHash(z); sqlite3ColumnPropertiesFromName(p, pCol); if( sType.n==0 ){ @@ -123707,9 +124502,14 @@ SQLITE_PRIVATE void sqlite3AddColumn(Parse *pParse, Token sName, Token sType){ pCol->affinity = sqlite3AffinityType(zType, pCol); pCol->colFlags |= COLFLAG_HASTYPE; } + if( p->nCol<=0xff ){ + u8 h = pCol->hName % sizeof(p->aHx); + p->aHx[h] = p->nCol; + } p->nCol++; p->nNVCol++; - pParse->constraintName.n = 0; + assert( pParse->isCreate ); + pParse->u1.cr.constraintName.n = 0; } /* @@ -123973,15 +124773,11 @@ SQLITE_PRIVATE void sqlite3AddPrimaryKey( assert( pCExpr!=0 ); sqlite3StringToId(pCExpr); if( pCExpr->op==TK_ID ){ - const char *zCName; assert( !ExprHasProperty(pCExpr, EP_IntValue) ); - zCName = pCExpr->u.zToken; - for(iCol=0; iColnCol; iCol++){ - if( sqlite3StrICmp(zCName, pTab->aCol[iCol].zCnName)==0 ){ - pCol = &pTab->aCol[iCol]; - makeColumnPartOfPrimaryKey(pParse, pCol); - break; - } + iCol = sqlite3ColumnIndex(pTab, pCExpr->u.zToken); + if( iCol>=0 ){ + pCol = &pTab->aCol[iCol]; + makeColumnPartOfPrimaryKey(pParse, pCol); } } } @@ -124033,8 +124829,10 @@ SQLITE_PRIVATE void sqlite3AddCheckConstraint( && !sqlite3BtreeIsReadonly(db->aDb[db->init.iDb].pBt) ){ pTab->pCheck = sqlite3ExprListAppend(pParse, pTab->pCheck, pCheckExpr); - if( pParse->constraintName.n ){ - sqlite3ExprListSetName(pParse, pTab->pCheck, &pParse->constraintName, 1); + assert( pParse->isCreate ); + if( pParse->u1.cr.constraintName.n ){ + sqlite3ExprListSetName(pParse, pTab->pCheck, + &pParse->u1.cr.constraintName, 1); }else{ Token t; for(zStart++; sqlite3Isspace(zStart[0]); zStart++){} @@ -124229,7 +125027,8 @@ static void identPut(char *z, int *pIdx, char *zSignedIdent){ ** from sqliteMalloc() and must be freed by the calling function. */ static char *createTableStmt(sqlite3 *db, Table *p){ - int i, k, n; + int i, k, len; + i64 n; char *zStmt; char *zSep, *zSep2, *zEnd; Column *pCol; @@ -124253,8 +125052,9 @@ static char *createTableStmt(sqlite3 *db, Table *p){ sqlite3OomFault(db); return 0; } - sqlite3_snprintf(n, zStmt, "CREATE TABLE "); - k = sqlite3Strlen30(zStmt); + assert( n>14 && n<=0x7fffffff ); + memcpy(zStmt, "CREATE TABLE ", 13); + k = 13; identPut(zStmt, &k, p->zName); zStmt[k++] = '('; for(pCol=p->aCol, i=0; inCol; i++, pCol++){ @@ -124266,13 +125066,15 @@ static char *createTableStmt(sqlite3 *db, Table *p){ /* SQLITE_AFF_REAL */ " REAL", /* SQLITE_AFF_FLEXNUM */ " NUM", }; - int len; const char *zType; - sqlite3_snprintf(n-k, &zStmt[k], zSep); - k += sqlite3Strlen30(&zStmt[k]); + len = sqlite3Strlen30(zSep); + assert( k+lenzCnName); + assert( kaffinity-SQLITE_AFF_BLOB >= 0 ); assert( pCol->affinity-SQLITE_AFF_BLOB < ArraySize(azType) ); testcase( pCol->affinity==SQLITE_AFF_BLOB ); @@ -124287,11 +125089,14 @@ static char *createTableStmt(sqlite3 *db, Table *p){ assert( pCol->affinity==SQLITE_AFF_BLOB || pCol->affinity==SQLITE_AFF_FLEXNUM || pCol->affinity==sqlite3AffinityType(zType, 0) ); + assert( k+lennColumn>=N ) return SQLITE_OK; + db = pParse->db; + assert( N>0 ); + assert( N <= SQLITE_MAX_COLUMN*2 /* tag-20250221-1 */ ); + testcase( N==2*pParse->db->aLimit[SQLITE_LIMIT_COLUMN] ); assert( pIdx->isResized==0 ); - nByte = (sizeof(char*) + sizeof(LogEst) + sizeof(i16) + 1)*N; + nByte = (sizeof(char*) + sizeof(LogEst) + sizeof(i16) + 1)*(u64)N; zExtra = sqlite3DbMallocZero(db, nByte); if( zExtra==0 ) return SQLITE_NOMEM_BKPT; memcpy(zExtra, pIdx->azColl, sizeof(char*)*pIdx->nColumn); @@ -124318,7 +125128,7 @@ static int resizeIndexObject(sqlite3 *db, Index *pIdx, int N){ zExtra += sizeof(i16)*N; memcpy(zExtra, pIdx->aSortOrder, pIdx->nColumn); pIdx->aSortOrder = (u8*)zExtra; - pIdx->nColumn = N; + pIdx->nColumn = (u16)N; /* See tag-20250221-1 above for proof of safety */ pIdx->isResized = 1; return SQLITE_OK; } @@ -124484,9 +125294,9 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){ ** into BTREE_BLOBKEY. */ assert( !pParse->bReturning ); - if( pParse->u1.addrCrTab ){ + if( pParse->u1.cr.addrCrTab ){ assert( v ); - sqlite3VdbeChangeP3(v, pParse->u1.addrCrTab, BTREE_BLOBKEY); + sqlite3VdbeChangeP3(v, pParse->u1.cr.addrCrTab, BTREE_BLOBKEY); } /* Locate the PRIMARY KEY index. Or, if this table was originally @@ -124572,14 +125382,14 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){ pIdx->nColumn = pIdx->nKeyCol; continue; } - if( resizeIndexObject(db, pIdx, pIdx->nKeyCol+n) ) return; + if( resizeIndexObject(pParse, pIdx, pIdx->nKeyCol+n) ) return; for(i=0, j=pIdx->nKeyCol; inKeyCol, pPk, i) ){ testcase( hasColumn(pIdx->aiColumn, pIdx->nKeyCol, pPk->aiColumn[i]) ); pIdx->aiColumn[j] = pPk->aiColumn[i]; pIdx->azColl[j] = pPk->azColl[i]; if( pPk->aSortOrder[i] ){ - /* See ticket https://www.sqlite.org/src/info/bba7b69f9849b5bf */ + /* See ticket https://sqlite.org/src/info/bba7b69f9849b5bf */ pIdx->bAscKeyBug = 1; } j++; @@ -124596,7 +125406,7 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){ if( !hasColumn(pPk->aiColumn, nPk, i) && (pTab->aCol[i].colFlags & COLFLAG_VIRTUAL)==0 ) nExtra++; } - if( resizeIndexObject(db, pPk, nPk+nExtra) ) return; + if( resizeIndexObject(pParse, pPk, nPk+nExtra) ) return; for(i=0, j=nPk; inCol; i++){ if( !hasColumn(pPk->aiColumn, j, i) && (pTab->aCol[i].colFlags & COLFLAG_VIRTUAL)==0 @@ -124926,7 +125736,7 @@ SQLITE_PRIVATE void sqlite3EndTable( /* If this is a CREATE TABLE xx AS SELECT ..., execute the SELECT ** statement to populate the new table. The root-page number for the - ** new table is in register pParse->regRoot. + ** new table is in register pParse->u1.cr.regRoot. ** ** Once the SELECT has been coded by sqlite3Select(), it is in a ** suitable state to query for the column names and types to be used @@ -124957,7 +125767,8 @@ SQLITE_PRIVATE void sqlite3EndTable( regRec = ++pParse->nMem; regRowid = ++pParse->nMem; sqlite3MayAbort(pParse); - sqlite3VdbeAddOp3(v, OP_OpenWrite, iCsr, pParse->regRoot, iDb); + assert( pParse->isCreate ); + sqlite3VdbeAddOp3(v, OP_OpenWrite, iCsr, pParse->u1.cr.regRoot, iDb); sqlite3VdbeChangeP5(v, OPFLAG_P2ISREG); addrTop = sqlite3VdbeCurrentAddr(v) + 1; sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, addrTop); @@ -125002,6 +125813,7 @@ SQLITE_PRIVATE void sqlite3EndTable( ** schema table. We just need to update that slot with all ** the information we've collected. */ + assert( pParse->isCreate ); sqlite3NestedParse(pParse, "UPDATE %Q." LEGACY_SCHEMA_TABLE " SET type='%s', name=%Q, tbl_name=%Q, rootpage=#%d, sql=%Q" @@ -125010,9 +125822,9 @@ SQLITE_PRIVATE void sqlite3EndTable( zType, p->zName, p->zName, - pParse->regRoot, + pParse->u1.cr.regRoot, zStmt, - pParse->regRowid + pParse->u1.cr.regRowid ); sqlite3DbFree(db, zStmt); sqlite3ChangeCookie(pParse, iDb); @@ -125752,7 +126564,7 @@ SQLITE_PRIVATE void sqlite3CreateForeignKey( }else{ nCol = pFromCol->nExpr; } - nByte = sizeof(*pFKey) + (nCol-1)*sizeof(pFKey->aCol[0]) + pTo->n + 1; + nByte = SZ_FKEY(nCol) + pTo->n + 1; if( pToCol ){ for(i=0; inExpr; i++){ nByte += sqlite3Strlen30(pToCol->a[i].zEName) + 1; @@ -125954,7 +126766,7 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){ ** not work for UNIQUE constraint indexes on WITHOUT ROWID tables ** with DESC primary keys, since those indexes have there keys in ** a different order from the main table. - ** See ticket: https://www.sqlite.org/src/info/bba7b69f9849b5bf + ** See ticket: https://sqlite.org/src/info/bba7b69f9849b5bf */ sqlite3VdbeAddOp1(v, OP_SeekEnd, iIdx); } @@ -125978,13 +126790,14 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){ */ SQLITE_PRIVATE Index *sqlite3AllocateIndexObject( sqlite3 *db, /* Database connection */ - i16 nCol, /* Total number of columns in the index */ + int nCol, /* Total number of columns in the index */ int nExtra, /* Number of bytes of extra space to alloc */ char **ppExtra /* Pointer to the "extra" space */ ){ Index *p; /* Allocated index object */ - int nByte; /* Bytes of space for Index object + arrays */ + i64 nByte; /* Bytes of space for Index object + arrays */ + assert( nCol <= 2*db->aLimit[SQLITE_LIMIT_COLUMN] ); nByte = ROUND8(sizeof(Index)) + /* Index structure */ ROUND8(sizeof(char*)*nCol) + /* Index.azColl */ ROUND8(sizeof(LogEst)*(nCol+1) + /* Index.aiRowLogEst */ @@ -125997,8 +126810,9 @@ SQLITE_PRIVATE Index *sqlite3AllocateIndexObject( p->aiRowLogEst = (LogEst*)pExtra; pExtra += sizeof(LogEst)*(nCol+1); p->aiColumn = (i16*)pExtra; pExtra += sizeof(i16)*nCol; p->aSortOrder = (u8*)pExtra; - p->nColumn = nCol; - p->nKeyCol = nCol - 1; + assert( nCol>0 ); + p->nColumn = (u16)nCol; + p->nKeyCol = (u16)(nCol - 1); *ppExtra = ((char*)p) + nByte; } return p; @@ -126336,6 +127150,7 @@ SQLITE_PRIVATE void sqlite3CreateIndex( assert( j<=0x7fff ); if( j<0 ){ j = pTab->iPKey; + pIndex->bIdxRowid = 1; }else{ if( pTab->aCol[j].notNull==0 ){ pIndex->uniqNotNull = 0; @@ -126809,12 +127624,11 @@ SQLITE_PRIVATE IdList *sqlite3IdListAppend(Parse *pParse, IdList *pList, Token * sqlite3 *db = pParse->db; int i; if( pList==0 ){ - pList = sqlite3DbMallocZero(db, sizeof(IdList) ); + pList = sqlite3DbMallocZero(db, SZ_IDLIST(1)); if( pList==0 ) return 0; }else{ IdList *pNew; - pNew = sqlite3DbRealloc(db, pList, - sizeof(IdList) + pList->nId*sizeof(pList->a)); + pNew = sqlite3DbRealloc(db, pList, SZ_IDLIST(pList->nId+1)); if( pNew==0 ){ sqlite3IdListDelete(db, pList); return 0; @@ -126913,8 +127727,7 @@ SQLITE_PRIVATE SrcList *sqlite3SrcListEnlarge( return 0; } if( nAlloc>SQLITE_MAX_SRCLIST ) nAlloc = SQLITE_MAX_SRCLIST; - pNew = sqlite3DbRealloc(db, pSrc, - sizeof(*pSrc) + (nAlloc-1)*sizeof(pSrc->a[0]) ); + pNew = sqlite3DbRealloc(db, pSrc, SZ_SRCLIST(nAlloc)); if( pNew==0 ){ assert( db->mallocFailed ); return 0; @@ -126989,7 +127802,7 @@ SQLITE_PRIVATE SrcList *sqlite3SrcListAppend( assert( pParse->db!=0 ); db = pParse->db; if( pList==0 ){ - pList = sqlite3DbMallocRawNN(pParse->db, sizeof(SrcList) ); + pList = sqlite3DbMallocRawNN(pParse->db, SZ_SRCLIST(1)); if( pList==0 ) return 0; pList->nAlloc = 1; pList->nSrc = 1; @@ -127875,10 +128688,9 @@ SQLITE_PRIVATE With *sqlite3WithAdd( } if( pWith ){ - sqlite3_int64 nByte = sizeof(*pWith) + (sizeof(pWith->a[1]) * pWith->nCte); - pNew = sqlite3DbRealloc(db, pWith, nByte); + pNew = sqlite3DbRealloc(db, pWith, SZ_WITH(pWith->nCte+1)); }else{ - pNew = sqlite3DbMallocZero(db, sizeof(*pWith)); + pNew = sqlite3DbMallocZero(db, SZ_WITH(1)); } assert( (pNew!=0 && zName!=0) || db->mallocFailed ); @@ -129852,11 +130664,6 @@ static void substrFunc( i64 p1, p2; assert( argc==3 || argc==2 ); - if( sqlite3_value_type(argv[1])==SQLITE_NULL - || (argc==3 && sqlite3_value_type(argv[2])==SQLITE_NULL) - ){ - return; - } p0type = sqlite3_value_type(argv[0]); p1 = sqlite3_value_int64(argv[1]); if( p0type==SQLITE_BLOB ){ @@ -129874,19 +130681,23 @@ static void substrFunc( } } } -#ifdef SQLITE_SUBSTR_COMPATIBILITY - /* If SUBSTR_COMPATIBILITY is defined then substr(X,0,N) work the same as - ** as substr(X,1,N) - it returns the first N characters of X. This - ** is essentially a back-out of the bug-fix in check-in [5fc125d362df4b8] - ** from 2009-02-02 for compatibility of applications that exploited the - ** old buggy behavior. */ - if( p1==0 ) p1 = 1; /* */ -#endif if( argc==3 ){ p2 = sqlite3_value_int64(argv[2]); + if( p2==0 && sqlite3_value_type(argv[2])==SQLITE_NULL ) return; }else{ p2 = sqlite3_context_db_handle(context)->aLimit[SQLITE_LIMIT_LENGTH]; } + if( p1==0 ){ +#ifdef SQLITE_SUBSTR_COMPATIBILITY + /* If SUBSTR_COMPATIBILITY is defined then substr(X,0,N) work the same as + ** as substr(X,1,N) - it returns the first N characters of X. This + ** is essentially a back-out of the bug-fix in check-in [5fc125d362df4b8] + ** from 2009-02-02 for compatibility of applications that exploited the + ** old buggy behavior. */ + p1 = 1; /* */ +#endif + if( sqlite3_value_type(argv[1])==SQLITE_NULL ) return; + } if( p1<0 ){ p1 += len; if( p1<0 ){ @@ -130587,7 +131398,7 @@ static const char hexdigits[] = { ** Append to pStr text that is the SQL literal representation of the ** value contained in pValue. */ -SQLITE_PRIVATE void sqlite3QuoteValue(StrAccum *pStr, sqlite3_value *pValue){ +SQLITE_PRIVATE void sqlite3QuoteValue(StrAccum *pStr, sqlite3_value *pValue, int bEscape){ /* As currently implemented, the string must be initially empty. ** we might relax this requirement in the future, but that will ** require enhancements to the implementation. */ @@ -130635,7 +131446,7 @@ SQLITE_PRIVATE void sqlite3QuoteValue(StrAccum *pStr, sqlite3_value *pValue){ } case SQLITE_TEXT: { const unsigned char *zArg = sqlite3_value_text(pValue); - sqlite3_str_appendf(pStr, "%Q", zArg); + sqlite3_str_appendf(pStr, bEscape ? "%#Q" : "%Q", zArg); break; } default: { @@ -130646,6 +131457,105 @@ SQLITE_PRIVATE void sqlite3QuoteValue(StrAccum *pStr, sqlite3_value *pValue){ } } +/* +** Return true if z[] begins with N hexadecimal digits, and write +** a decoding of those digits into *pVal. Or return false if any +** one of the first N characters in z[] is not a hexadecimal digit. +*/ +static int isNHex(const char *z, int N, u32 *pVal){ + int i; + int v = 0; + for(i=0; i0 ){ + memmove(&zOut[j], &zIn[i], n); + j += n; + i += n; + } + if( zIn[i+1]=='\\' ){ + i += 2; + zOut[j++] = '\\'; + }else if( sqlite3Isxdigit(zIn[i+1]) ){ + if( !isNHex(&zIn[i+1], 4, &v) ) goto unistr_error; + i += 5; + j += sqlite3AppendOneUtf8Character(&zOut[j], v); + }else if( zIn[i+1]=='+' ){ + if( !isNHex(&zIn[i+2], 6, &v) ) goto unistr_error; + i += 8; + j += sqlite3AppendOneUtf8Character(&zOut[j], v); + }else if( zIn[i+1]=='u' ){ + if( !isNHex(&zIn[i+2], 4, &v) ) goto unistr_error; + i += 6; + j += sqlite3AppendOneUtf8Character(&zOut[j], v); + }else if( zIn[i+1]=='U' ){ + if( !isNHex(&zIn[i+2], 8, &v) ) goto unistr_error; + i += 10; + j += sqlite3AppendOneUtf8Character(&zOut[j], v); + }else{ + goto unistr_error; + } + } + zOut[j] = 0; + sqlite3_result_text64(context, zOut, j, sqlite3_free, SQLITE_UTF8); + return; + +unistr_error: + sqlite3_free(zOut); + sqlite3_result_error(context, "invalid Unicode escape", -1); + return; +} + + /* ** Implementation of the QUOTE() function. ** @@ -130655,6 +131565,10 @@ SQLITE_PRIVATE void sqlite3QuoteValue(StrAccum *pStr, sqlite3_value *pValue){ ** as needed. BLOBs are encoded as hexadecimal literals. Strings with ** embedded NUL characters cannot be represented as string literals in SQL ** and hence the returned string literal is truncated prior to the first NUL. +** +** If sqlite3_user_data() is non-zero, then the UNISTR_QUOTE() function is +** implemented instead. The difference is that UNISTR_QUOTE() uses the +** UNISTR() function to escape control characters. */ static void quoteFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ sqlite3_str str; @@ -130662,7 +131576,7 @@ static void quoteFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ assert( argc==1 ); UNUSED_PARAMETER(argc); sqlite3StrAccumInit(&str, db, 0, 0, db->aLimit[SQLITE_LIMIT_LENGTH]); - sqlite3QuoteValue(&str,argv[0]); + sqlite3QuoteValue(&str,argv[0],SQLITE_PTR_TO_INT(sqlite3_user_data(context))); sqlite3_result_text(context, sqlite3StrAccumFinish(&str), str.nChar, SQLITE_DYNAMIC); if( str.accError!=SQLITE_OK ){ @@ -130917,7 +131831,7 @@ static void replaceFunc( assert( zRep==sqlite3_value_text(argv[2]) ); nOut = nStr + 1; assert( nOutselFlags); } pSelect = sqlite3SelectNew(pParse, pRow, 0, 0, 0, 0, 0, f, 0); - pLeft->selFlags &= ~SF_MultiValue; + pLeft->selFlags &= ~(u32)SF_MultiValue; if( pSelect ){ pSelect->op = TK_ALL; pSelect->pPrior = pLeft; @@ -134902,28 +135818,22 @@ SQLITE_PRIVATE void sqlite3Insert( aTabColMap = sqlite3DbMallocZero(db, pTab->nCol*sizeof(int)); if( aTabColMap==0 ) goto insert_cleanup; for(i=0; inId; i++){ - const char *zCName = pColumn->a[i].zName; - u8 hName = sqlite3StrIHash(zCName); - for(j=0; jnCol; j++){ - if( pTab->aCol[j].hName!=hName ) continue; - if( sqlite3StrICmp(zCName, pTab->aCol[j].zCnName)==0 ){ - if( aTabColMap[j]==0 ) aTabColMap[j] = i+1; - if( i!=j ) bIdListInOrder = 0; - if( j==pTab->iPKey ){ - ipkColumn = i; assert( !withoutRowid ); - } + j = sqlite3ColumnIndex(pTab, pColumn->a[i].zName); + if( j>=0 ){ + if( aTabColMap[j]==0 ) aTabColMap[j] = i+1; + if( i!=j ) bIdListInOrder = 0; + if( j==pTab->iPKey ){ + ipkColumn = i; assert( !withoutRowid ); + } #ifndef SQLITE_OMIT_GENERATED_COLUMNS - if( pTab->aCol[j].colFlags & (COLFLAG_STORED|COLFLAG_VIRTUAL) ){ - sqlite3ErrorMsg(pParse, - "cannot INSERT into generated column \"%s\"", - pTab->aCol[j].zCnName); - goto insert_cleanup; - } -#endif - break; + if( pTab->aCol[j].colFlags & (COLFLAG_STORED|COLFLAG_VIRTUAL) ){ + sqlite3ErrorMsg(pParse, + "cannot INSERT into generated column \"%s\"", + pTab->aCol[j].zCnName); + goto insert_cleanup; } - } - if( j>=pTab->nCol ){ +#endif + }else{ if( sqlite3IsRowid(pColumn->a[i].zName) && !withoutRowid ){ ipkColumn = i; bIdListInOrder = 0; @@ -135221,7 +136131,7 @@ SQLITE_PRIVATE void sqlite3Insert( continue; }else if( pColumn==0 ){ /* Hidden columns that are not explicitly named in the INSERT - ** get there default value */ + ** get their default value */ sqlite3ExprCodeFactorable(pParse, sqlite3ColumnExpr(pTab, &pTab->aCol[i]), iRegStore); @@ -135946,7 +136856,7 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks( ** could happen in any order, but they are grouped up front for ** convenience. ** - ** 2018-08-14: Ticket https://www.sqlite.org/src/info/908f001483982c43 + ** 2018-08-14: Ticket https://sqlite.org/src/info/908f001483982c43 ** The order of constraints used to have OE_Update as (2) and OE_Abort ** and so forth as (1). But apparently PostgreSQL checks the OE_Update ** constraint before any others, so it had to be moved. @@ -137756,6 +138666,8 @@ struct sqlite3_api_routines { /* Version 3.44.0 and later */ void *(*get_clientdata)(sqlite3*,const char*); int (*set_clientdata)(sqlite3*, const char*, void*, void(*)(void*)); + /* Version 3.50.0 and later */ + int (*setlk_timeout)(sqlite3*,int,int); }; /* @@ -138089,6 +139001,8 @@ typedef int (*sqlite3_loadext_entry)( /* Version 3.44.0 and later */ #define sqlite3_get_clientdata sqlite3_api->get_clientdata #define sqlite3_set_clientdata sqlite3_api->set_clientdata +/* Version 3.50.0 and later */ +#define sqlite3_setlk_timeout sqlite3_api->setlk_timeout #endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */ #if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) @@ -138610,7 +139524,9 @@ static const sqlite3_api_routines sqlite3Apis = { sqlite3_stmt_explain, /* Version 3.44.0 and later */ sqlite3_get_clientdata, - sqlite3_set_clientdata + sqlite3_set_clientdata, + /* Version 3.50.0 and later */ + sqlite3_setlk_timeout }; /* True if x is the directory separator character @@ -139132,48 +140048,48 @@ static const char *const pragCName[] = { /* 13 */ "pk", /* 14 */ "hidden", /* table_info reuses 8 */ - /* 15 */ "schema", /* Used by: table_list */ - /* 16 */ "name", + /* 15 */ "name", /* Used by: function_list */ + /* 16 */ "builtin", /* 17 */ "type", - /* 18 */ "ncol", - /* 19 */ "wr", - /* 20 */ "strict", - /* 21 */ "seqno", /* Used by: index_xinfo */ - /* 22 */ "cid", - /* 23 */ "name", - /* 24 */ "desc", - /* 25 */ "coll", - /* 26 */ "key", - /* 27 */ "name", /* Used by: function_list */ - /* 28 */ "builtin", - /* 29 */ "type", - /* 30 */ "enc", - /* 31 */ "narg", - /* 32 */ "flags", - /* 33 */ "tbl", /* Used by: stats */ - /* 34 */ "idx", - /* 35 */ "wdth", - /* 36 */ "hght", - /* 37 */ "flgs", - /* 38 */ "seq", /* Used by: index_list */ - /* 39 */ "name", - /* 40 */ "unique", - /* 41 */ "origin", - /* 42 */ "partial", + /* 18 */ "enc", + /* 19 */ "narg", + /* 20 */ "flags", + /* 21 */ "schema", /* Used by: table_list */ + /* 22 */ "name", + /* 23 */ "type", + /* 24 */ "ncol", + /* 25 */ "wr", + /* 26 */ "strict", + /* 27 */ "seqno", /* Used by: index_xinfo */ + /* 28 */ "cid", + /* 29 */ "name", + /* 30 */ "desc", + /* 31 */ "coll", + /* 32 */ "key", + /* 33 */ "seq", /* Used by: index_list */ + /* 34 */ "name", + /* 35 */ "unique", + /* 36 */ "origin", + /* 37 */ "partial", + /* 38 */ "tbl", /* Used by: stats */ + /* 39 */ "idx", + /* 40 */ "wdth", + /* 41 */ "hght", + /* 42 */ "flgs", /* 43 */ "table", /* Used by: foreign_key_check */ /* 44 */ "rowid", /* 45 */ "parent", /* 46 */ "fkid", - /* index_info reuses 21 */ - /* 47 */ "seq", /* Used by: database_list */ - /* 48 */ "name", - /* 49 */ "file", - /* 50 */ "busy", /* Used by: wal_checkpoint */ - /* 51 */ "log", - /* 52 */ "checkpointed", - /* collation_list reuses 38 */ + /* 47 */ "busy", /* Used by: wal_checkpoint */ + /* 48 */ "log", + /* 49 */ "checkpointed", + /* 50 */ "seq", /* Used by: database_list */ + /* 51 */ "name", + /* 52 */ "file", + /* index_info reuses 27 */ /* 53 */ "database", /* Used by: lock_status */ /* 54 */ "status", + /* collation_list reuses 33 */ /* 55 */ "cache_size", /* Used by: default_cache_size */ /* module_list pragma_list reuses 9 */ /* 56 */ "timeout", /* Used by: busy_timeout */ @@ -139266,7 +140182,7 @@ static const PragmaName aPragmaName[] = { {/* zName: */ "collation_list", /* ePragTyp: */ PragTyp_COLLATION_LIST, /* ePragFlg: */ PragFlg_Result0, - /* ColNames: */ 38, 2, + /* ColNames: */ 33, 2, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_COMPILEOPTION_DIAGS) @@ -139301,7 +140217,7 @@ static const PragmaName aPragmaName[] = { {/* zName: */ "database_list", /* ePragTyp: */ PragTyp_DATABASE_LIST, /* ePragFlg: */ PragFlg_Result0, - /* ColNames: */ 47, 3, + /* ColNames: */ 50, 3, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && !defined(SQLITE_OMIT_DEPRECATED) @@ -139381,7 +140297,7 @@ static const PragmaName aPragmaName[] = { {/* zName: */ "function_list", /* ePragTyp: */ PragTyp_FUNCTION_LIST, /* ePragFlg: */ PragFlg_Result0, - /* ColNames: */ 27, 6, + /* ColNames: */ 15, 6, /* iArg: */ 0 }, #endif #endif @@ -139410,17 +140326,17 @@ static const PragmaName aPragmaName[] = { {/* zName: */ "index_info", /* ePragTyp: */ PragTyp_INDEX_INFO, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt, - /* ColNames: */ 21, 3, + /* ColNames: */ 27, 3, /* iArg: */ 0 }, {/* zName: */ "index_list", /* ePragTyp: */ PragTyp_INDEX_LIST, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt, - /* ColNames: */ 38, 5, + /* ColNames: */ 33, 5, /* iArg: */ 0 }, {/* zName: */ "index_xinfo", /* ePragTyp: */ PragTyp_INDEX_INFO, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt, - /* ColNames: */ 21, 6, + /* ColNames: */ 27, 6, /* iArg: */ 1 }, #endif #if !defined(SQLITE_OMIT_INTEGRITY_CHECK) @@ -139599,7 +140515,7 @@ static const PragmaName aPragmaName[] = { {/* zName: */ "stats", /* ePragTyp: */ PragTyp_STATS, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq, - /* ColNames: */ 33, 5, + /* ColNames: */ 38, 5, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) @@ -139618,7 +140534,7 @@ static const PragmaName aPragmaName[] = { {/* zName: */ "table_list", /* ePragTyp: */ PragTyp_TABLE_LIST, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1, - /* ColNames: */ 15, 6, + /* ColNames: */ 21, 6, /* iArg: */ 0 }, {/* zName: */ "table_xinfo", /* ePragTyp: */ PragTyp_TABLE_INFO, @@ -139695,7 +140611,7 @@ static const PragmaName aPragmaName[] = { {/* zName: */ "wal_checkpoint", /* ePragTyp: */ PragTyp_WAL_CHECKPOINT, /* ePragFlg: */ PragFlg_NeedSchema, - /* ColNames: */ 50, 3, + /* ColNames: */ 47, 3, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_FLAG_PRAGMAS) @@ -139717,7 +140633,7 @@ static const PragmaName aPragmaName[] = { ** the following macro or to the actual analysis_limit if it is non-zero, ** in order to prevent PRAGMA optimize from running for too long. ** -** The value of 2000 is chosen emperically so that the worst-case run-time +** The value of 2000 is chosen empirically so that the worst-case run-time ** for PRAGMA optimize does not exceed 100 milliseconds against a variety ** of test databases on a RaspberryPI-4 compiled using -Os and without ** -DSQLITE_DEBUG. Of course, your mileage may vary. For the purpose of @@ -140834,7 +141750,10 @@ SQLITE_PRIVATE void sqlite3Pragma( } }else{ db->flags &= ~mask; - if( mask==SQLITE_DeferFKs ) db->nDeferredImmCons = 0; + if( mask==SQLITE_DeferFKs ){ + db->nDeferredImmCons = 0; + db->nDeferredCons = 0; + } if( (mask & SQLITE_WriteSchema)!=0 && sqlite3_stricmp(zRight, "reset")==0 ){ @@ -144003,7 +144922,7 @@ SQLITE_PRIVATE Select *sqlite3SelectNew( pNew->addrOpenEphm[0] = -1; pNew->addrOpenEphm[1] = -1; pNew->nSelectRow = 0; - if( pSrc==0 ) pSrc = sqlite3DbMallocZero(pParse->db, sizeof(*pSrc)); + if( pSrc==0 ) pSrc = sqlite3DbMallocZero(pParse->db, SZ_SRCLIST_1); pNew->pSrc = pSrc; pNew->pWhere = pWhere; pNew->pGroupBy = pGroupBy; @@ -144168,10 +145087,33 @@ SQLITE_PRIVATE int sqlite3JoinType(Parse *pParse, Token *pA, Token *pB, Token *p */ SQLITE_PRIVATE int sqlite3ColumnIndex(Table *pTab, const char *zCol){ int i; - u8 h = sqlite3StrIHash(zCol); - Column *pCol; - for(pCol=pTab->aCol, i=0; inCol; pCol++, i++){ - if( pCol->hName==h && sqlite3StrICmp(pCol->zCnName, zCol)==0 ) return i; + u8 h; + const Column *aCol; + int nCol; + + h = sqlite3StrIHash(zCol); + aCol = pTab->aCol; + nCol = pTab->nCol; + + /* See if the aHx gives us a lucky match */ + i = pTab->aHx[h % sizeof(pTab->aHx)]; + assert( i=nCol ) break; } return -1; } @@ -145363,8 +146305,8 @@ static void selectInnerLoop( ** X extra columns. */ SQLITE_PRIVATE KeyInfo *sqlite3KeyInfoAlloc(sqlite3 *db, int N, int X){ - int nExtra = (N+X)*(sizeof(CollSeq*)+1) - sizeof(CollSeq*); - KeyInfo *p = sqlite3DbMallocRawNN(db, sizeof(KeyInfo) + nExtra); + int nExtra = (N+X)*(sizeof(CollSeq*)+1); + KeyInfo *p = sqlite3DbMallocRawNN(db, SZ_KEYINFO(0) + nExtra); if( p ){ p->aSortFlags = (u8*)&p->aColl[N+X]; p->nKeyField = (u16)N; @@ -145372,7 +146314,7 @@ SQLITE_PRIVATE KeyInfo *sqlite3KeyInfoAlloc(sqlite3 *db, int N, int X){ p->enc = ENC(db); p->db = db; p->nRef = 1; - memset(&p[1], 0, nExtra); + memset(p->aColl, 0, nExtra); }else{ return (KeyInfo*)sqlite3OomFault(db); } @@ -147073,6 +148015,7 @@ static int multiSelect( multi_select_end: pDest->iSdst = dest.iSdst; pDest->nSdst = dest.nSdst; + pDest->iSDParm2 = dest.iSDParm2; if( pDelete ){ sqlite3ParserAddCleanup(pParse, sqlite3SelectDeleteGeneric, pDelete); } @@ -148683,7 +149626,8 @@ static void constInsert( return; /* Already present. Return without doing anything. */ } } - if( sqlite3ExprAffinity(pColumn)==SQLITE_AFF_BLOB ){ + assert( SQLITE_AFF_NONEbHasAffBlob = 1; } @@ -148758,7 +149702,8 @@ static int propagateConstantExprRewriteOne( if( pColumn==pExpr ) continue; if( pColumn->iTable!=pExpr->iTable ) continue; if( pColumn->iColumn!=pExpr->iColumn ) continue; - if( bIgnoreAffBlob && sqlite3ExprAffinity(pColumn)==SQLITE_AFF_BLOB ){ + assert( SQLITE_AFF_NONEpWinDefn = 0; #endif - p->selFlags &= ~SF_Compound; + p->selFlags &= ~(u32)SF_Compound; assert( (p->selFlags & SF_Converted)==0 ); p->selFlags |= SF_Converted; assert( pNew->pPrior!=0 ); @@ -149888,7 +150833,7 @@ static int selectExpander(Walker *pWalker, Select *p){ pEList = p->pEList; if( pParse->pWith && (p->selFlags & SF_View) ){ if( p->pWith==0 ){ - p->pWith = (With*)sqlite3DbMallocZero(db, sizeof(With)); + p->pWith = (With*)sqlite3DbMallocZero(db, SZ_WITH(1) ); if( p->pWith==0 ){ return WRC_Abort; } @@ -151027,6 +151972,7 @@ static void agginfoFree(sqlite3 *db, void *pArg){ ** * There is no WHERE or GROUP BY or HAVING clauses on the subqueries ** * The outer query is a simple count(*) with no WHERE clause or other ** extraneous syntax. +** * None of the subqueries are DISTINCT (forumpost/a860f5fb2e 2025-03-10) ** ** Return TRUE if the optimization is undertaken. */ @@ -151059,7 +152005,11 @@ static int countOfViewOptimization(Parse *pParse, Select *p){ if( pSub->op!=TK_ALL && pSub->pPrior ) return 0; /* Must be UNION ALL */ if( pSub->pWhere ) return 0; /* No WHERE clause */ if( pSub->pLimit ) return 0; /* No LIMIT clause */ - if( pSub->selFlags & SF_Aggregate ) return 0; /* Not an aggregate */ + if( pSub->selFlags & (SF_Aggregate|SF_Distinct) ){ + testcase( pSub->selFlags & SF_Aggregate ); + testcase( pSub->selFlags & SF_Distinct ); + return 0; /* Not an aggregate nor DISTINCT */ + } assert( pSub->pHaving==0 ); /* Due to the previous */ pSub = pSub->pPrior; /* Repeat over compound */ }while( pSub ); @@ -151071,14 +152021,14 @@ static int countOfViewOptimization(Parse *pParse, Select *p){ pExpr = 0; pSub = sqlite3SubqueryDetach(db, pFrom); sqlite3SrcListDelete(db, p->pSrc); - p->pSrc = sqlite3DbMallocZero(pParse->db, sizeof(*p->pSrc)); + p->pSrc = sqlite3DbMallocZero(pParse->db, SZ_SRCLIST_1); while( pSub ){ Expr *pTerm; pPrior = pSub->pPrior; pSub->pPrior = 0; pSub->pNext = 0; pSub->selFlags |= SF_Aggregate; - pSub->selFlags &= ~SF_Compound; + pSub->selFlags &= ~(u32)SF_Compound; pSub->nSelectRow = 0; sqlite3ParserAddCleanup(pParse, sqlite3ExprListDeleteGeneric, pSub->pEList); pTerm = pPrior ? sqlite3ExprDup(db, pCount, 0) : pCount; @@ -151093,7 +152043,7 @@ static int countOfViewOptimization(Parse *pParse, Select *p){ pSub = pPrior; } p->pEList->a[0].pExpr = pExpr; - p->selFlags &= ~SF_Aggregate; + p->selFlags &= ~(u32)SF_Aggregate; #if TREETRACE_ENABLED if( sqlite3TreeTrace & 0x200 ){ @@ -151300,7 +152250,7 @@ SQLITE_PRIVATE int sqlite3Select( testcase( pParse->earlyCleanup ); p->pOrderBy = 0; } - p->selFlags &= ~SF_Distinct; + p->selFlags &= ~(u32)SF_Distinct; p->selFlags |= SF_NoopOrderBy; } sqlite3SelectPrep(pParse, p, 0); @@ -151339,7 +152289,7 @@ SQLITE_PRIVATE int sqlite3Select( ** and leaving this flag set can cause errors if a compound sub-query ** in p->pSrc is flattened into this query and this function called ** again as part of compound SELECT processing. */ - p->selFlags &= ~SF_UFSrcCheck; + p->selFlags &= ~(u32)SF_UFSrcCheck; } if( pDest->eDest==SRT_Output ){ @@ -151828,7 +152778,7 @@ SQLITE_PRIVATE int sqlite3Select( && p->pWin==0 #endif ){ - p->selFlags &= ~SF_Distinct; + p->selFlags &= ~(u32)SF_Distinct; pGroupBy = p->pGroupBy = sqlite3ExprListDup(db, pEList, 0); if( pGroupBy ){ for(i=0; inExpr; i++){ @@ -151937,6 +152887,12 @@ SQLITE_PRIVATE int sqlite3Select( if( pWInfo==0 ) goto select_end; if( sqlite3WhereOutputRowCount(pWInfo) < p->nSelectRow ){ p->nSelectRow = sqlite3WhereOutputRowCount(pWInfo); + if( pDest->eDest<=SRT_DistQueue && pDest->eDest>=SRT_DistFifo ){ + /* TUNING: For a UNION CTE, because UNION is implies DISTINCT, + ** reduce the estimated output row count by 8 (LogEst 30). + ** Search for tag-20250414a to see other cases */ + p->nSelectRow -= 30; + } } if( sDistinct.isTnct && sqlite3WhereIsDistinct(pWInfo) ){ sDistinct.eTnctType = sqlite3WhereIsDistinct(pWInfo); @@ -152310,6 +153266,10 @@ SQLITE_PRIVATE int sqlite3Select( if( iOrderByCol ){ Expr *pX = p->pEList->a[iOrderByCol-1].pExpr; Expr *pBase = sqlite3ExprSkipCollateAndLikely(pX); + while( ALWAYS(pBase!=0) && pBase->op==TK_IF_NULL_ROW ){ + pX = pBase->pLeft; + pBase = sqlite3ExprSkipCollateAndLikely(pX); + } if( ALWAYS(pBase!=0) && pBase->op!=TK_AGG_COLUMN && pBase->op!=TK_REGISTER @@ -152893,7 +153853,8 @@ SQLITE_PRIVATE Trigger *sqlite3TriggerList(Parse *pParse, Table *pTab){ assert( pParse->db->pVtabCtx==0 ); #endif assert( pParse->bReturning ); - assert( &(pParse->u1.pReturning->retTrig) == pTrig ); + assert( !pParse->isCreate ); + assert( &(pParse->u1.d.pReturning->retTrig) == pTrig ); pTrig->table = pTab->zName; pTrig->pTabSchema = pTab->pSchema; pTrig->pNext = pList; @@ -153861,7 +154822,8 @@ static void codeReturningTrigger( ExprList *pNew; Returning *pReturning; Select sSelect; - SrcList sFrom; + SrcList *pFrom; + u8 fromSpace[SZ_SRCLIST_1]; assert( v!=0 ); if( !pParse->bReturning ){ @@ -153870,19 +154832,21 @@ static void codeReturningTrigger( return; } assert( db->pParse==pParse ); - pReturning = pParse->u1.pReturning; + assert( !pParse->isCreate ); + pReturning = pParse->u1.d.pReturning; if( pTrigger != &(pReturning->retTrig) ){ /* This RETURNING trigger is for a different statement */ return; } memset(&sSelect, 0, sizeof(sSelect)); - memset(&sFrom, 0, sizeof(sFrom)); + pFrom = (SrcList*)fromSpace; + memset(pFrom, 0, SZ_SRCLIST_1); sSelect.pEList = sqlite3ExprListDup(db, pReturning->pReturnEL, 0); - sSelect.pSrc = &sFrom; - sFrom.nSrc = 1; - sFrom.a[0].pSTab = pTab; - sFrom.a[0].zName = pTab->zName; /* tag-20240424-1 */ - sFrom.a[0].iCursor = -1; + sSelect.pSrc = pFrom; + pFrom->nSrc = 1; + pFrom->a[0].pSTab = pTab; + pFrom->a[0].zName = pTab->zName; /* tag-20240424-1 */ + pFrom->a[0].iCursor = -1; sqlite3SelectPrep(pParse, &sSelect, 0); if( pParse->nErr==0 ){ assert( db->mallocFailed==0 ); @@ -154100,6 +155064,8 @@ static TriggerPrg *codeRowTrigger( sSubParse.eTriggerOp = pTrigger->op; sSubParse.nQueryLoop = pParse->nQueryLoop; sSubParse.prepFlags = pParse->prepFlags; + sSubParse.oldmask = 0; + sSubParse.newmask = 0; v = sqlite3GetVdbe(&sSubParse); if( v ){ @@ -154854,38 +155820,32 @@ SQLITE_PRIVATE void sqlite3Update( */ chngRowid = chngPk = 0; for(i=0; inExpr; i++){ - u8 hCol = sqlite3StrIHash(pChanges->a[i].zEName); /* If this is an UPDATE with a FROM clause, do not resolve expressions ** here. The call to sqlite3Select() below will do that. */ if( nChangeFrom==0 && sqlite3ResolveExprNames(&sNC, pChanges->a[i].pExpr) ){ goto update_cleanup; } - for(j=0; jnCol; j++){ - if( pTab->aCol[j].hName==hCol - && sqlite3StrICmp(pTab->aCol[j].zCnName, pChanges->a[i].zEName)==0 - ){ - if( j==pTab->iPKey ){ - chngRowid = 1; - pRowidExpr = pChanges->a[i].pExpr; - iRowidExpr = i; - }else if( pPk && (pTab->aCol[j].colFlags & COLFLAG_PRIMKEY)!=0 ){ - chngPk = 1; - } + j = sqlite3ColumnIndex(pTab, pChanges->a[i].zEName); + if( j>=0 ){ + if( j==pTab->iPKey ){ + chngRowid = 1; + pRowidExpr = pChanges->a[i].pExpr; + iRowidExpr = i; + }else if( pPk && (pTab->aCol[j].colFlags & COLFLAG_PRIMKEY)!=0 ){ + chngPk = 1; + } #ifndef SQLITE_OMIT_GENERATED_COLUMNS - else if( pTab->aCol[j].colFlags & COLFLAG_GENERATED ){ - testcase( pTab->aCol[j].colFlags & COLFLAG_VIRTUAL ); - testcase( pTab->aCol[j].colFlags & COLFLAG_STORED ); - sqlite3ErrorMsg(pParse, - "cannot UPDATE generated column \"%s\"", - pTab->aCol[j].zCnName); - goto update_cleanup; - } -#endif - aXRef[j] = i; - break; + else if( pTab->aCol[j].colFlags & COLFLAG_GENERATED ){ + testcase( pTab->aCol[j].colFlags & COLFLAG_VIRTUAL ); + testcase( pTab->aCol[j].colFlags & COLFLAG_STORED ); + sqlite3ErrorMsg(pParse, + "cannot UPDATE generated column \"%s\"", + pTab->aCol[j].zCnName); + goto update_cleanup; } - } - if( j>=pTab->nCol ){ +#endif + aXRef[j] = i; + }else{ if( pPk==0 && sqlite3IsRowid(pChanges->a[i].zEName) ){ j = -1; chngRowid = 1; @@ -156208,7 +157168,7 @@ SQLITE_PRIVATE void sqlite3Vacuum(Parse *pParse, Token *pNm, Expr *pInto){ #else /* When SQLITE_BUG_COMPATIBLE_20160819 is defined, unrecognized arguments ** to VACUUM are silently ignored. This is a back-out of a bug fix that - ** occurred on 2016-08-19 (https://www.sqlite.org/src/info/083f9e6270). + ** occurred on 2016-08-19 (https://sqlite.org/src/info/083f9e6270). ** The buggy behavior is required for binary compatibility with some ** legacy applications. */ iDb = sqlite3FindDb(pParse->db, pNm); @@ -156287,7 +157247,7 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3RunVacuum( saved_nChange = db->nChange; saved_nTotalChange = db->nTotalChange; saved_mTrace = db->mTrace; - db->flags |= SQLITE_WriteSchema | SQLITE_IgnoreChecks; + db->flags |= SQLITE_WriteSchema | SQLITE_IgnoreChecks | SQLITE_Comments; db->mDbFlags |= DBFLAG_PreferBuiltin | DBFLAG_Vacuum; db->flags &= ~(u64)(SQLITE_ForeignKeys | SQLITE_ReverseOrder | SQLITE_Defensive | SQLITE_CountRows); @@ -156992,11 +157952,12 @@ SQLITE_PRIVATE void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){ ** schema table. We just need to update that slot with all ** the information we've collected. ** - ** The VM register number pParse->regRowid holds the rowid of an + ** The VM register number pParse->u1.cr.regRowid holds the rowid of an ** entry in the sqlite_schema table that was created for this vtab ** by sqlite3StartTable(). */ iDb = sqlite3SchemaToIndex(db, pTab->pSchema); + assert( pParse->isCreate ); sqlite3NestedParse(pParse, "UPDATE %Q." LEGACY_SCHEMA_TABLE " " "SET type='table', name=%Q, tbl_name=%Q, rootpage=0, sql=%Q " @@ -157005,7 +157966,7 @@ SQLITE_PRIVATE void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){ pTab->zName, pTab->zName, zStmt, - pParse->regRowid + pParse->u1.cr.regRowid ); v = sqlite3GetVdbe(pParse); sqlite3ChangeCookie(pParse, iDb); @@ -158415,9 +159376,14 @@ struct WhereInfo { Bitmask revMask; /* Mask of ORDER BY terms that need reversing */ WhereClause sWC; /* Decomposition of the WHERE clause */ WhereMaskSet sMaskSet; /* Map cursor numbers to bitmasks */ - WhereLevel a[1]; /* Information about each nest loop in WHERE */ + WhereLevel a[FLEXARRAY]; /* Information about each nest loop in WHERE */ }; +/* +** The size (in bytes) of a WhereInfo object that holds N WhereLevels. +*/ +#define SZ_WHEREINFO(N) ROUND8(offsetof(WhereInfo,a)+(N)*sizeof(WhereLevel)) + /* ** Private interfaces - callable only by other where.c routines. ** @@ -159097,7 +160063,7 @@ static void adjustOrderByCol(ExprList *pOrderBy, ExprList *pEList){ /* ** pX is an expression of the form: (vector) IN (SELECT ...) ** In other words, it is a vector IN operator with a SELECT clause on the -** LHS. But not all terms in the vector are indexable and the terms might +** RHS. But not all terms in the vector are indexable and the terms might ** not be in the correct order for indexing. ** ** This routine makes a copy of the input pX expression and then adjusts @@ -160163,6 +161129,9 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( } sqlite3VdbeAddOp2(v, OP_Integer, pLoop->u.vtab.idxNum, iReg); sqlite3VdbeAddOp2(v, OP_Integer, nConstraint, iReg+1); + /* The instruction immediately prior to OP_VFilter must be an OP_Integer + ** that sets the "argc" value for xVFilter. This is necessary for + ** resolveP2() to work correctly. See tag-20250207a. */ sqlite3VdbeAddOp4(v, OP_VFilter, iCur, addrNotFound, iReg, pLoop->u.vtab.idxStr, pLoop->u.vtab.needFree ? P4_DYNAMIC : P4_STATIC); @@ -160865,8 +161834,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( int nNotReady; /* The number of notReady tables */ SrcItem *origSrc; /* Original list of tables */ nNotReady = pWInfo->nLevel - iLevel - 1; - pOrTab = sqlite3DbMallocRawNN(db, - sizeof(*pOrTab)+ nNotReady*sizeof(pOrTab->a[0])); + pOrTab = sqlite3DbMallocRawNN(db, SZ_SRCLIST(nNotReady+1)); if( pOrTab==0 ) return notReady; pOrTab->nAlloc = (u8)(nNotReady + 1); pOrTab->nSrc = pOrTab->nAlloc; @@ -160917,7 +161885,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( ** ** This optimization also only applies if the (x1 OR x2 OR ...) term ** is not contained in the ON clause of a LEFT JOIN. - ** See ticket http://www.sqlite.org/src/info/f2369304e4 + ** See ticket http://sqlite.org/src/info/f2369304e4 ** ** 2022-02-04: Do not push down slices of a row-value comparison. ** In other words, "w" or "y" may not be a slice of a vector. Otherwise, @@ -161409,7 +162377,8 @@ SQLITE_PRIVATE SQLITE_NOINLINE void sqlite3WhereRightJoinLoop( WhereInfo *pSubWInfo; WhereLoop *pLoop = pLevel->pWLoop; SrcItem *pTabItem = &pWInfo->pTabList->a[pLevel->iFrom]; - SrcList sFrom; + SrcList *pFrom; + u8 fromSpace[SZ_SRCLIST_1]; Bitmask mAll = 0; int k; @@ -161453,13 +162422,14 @@ SQLITE_PRIVATE SQLITE_NOINLINE void sqlite3WhereRightJoinLoop( sqlite3ExprDup(pParse->db, pTerm->pExpr, 0)); } } - sFrom.nSrc = 1; - sFrom.nAlloc = 1; - memcpy(&sFrom.a[0], pTabItem, sizeof(SrcItem)); - sFrom.a[0].fg.jointype = 0; + pFrom = (SrcList*)fromSpace; + pFrom->nSrc = 1; + pFrom->nAlloc = 1; + memcpy(&pFrom->a[0], pTabItem, sizeof(SrcItem)); + pFrom->a[0].fg.jointype = 0; assert( pParse->withinRJSubrtn < 100 ); pParse->withinRJSubrtn++; - pSubWInfo = sqlite3WhereBegin(pParse, &sFrom, pSubWhere, 0, 0, 0, + pSubWInfo = sqlite3WhereBegin(pParse, pFrom, pSubWhere, 0, 0, 0, WHERE_RIGHT_JOIN, 0); if( pSubWInfo ){ int iCur = pLevel->iTabCur; @@ -163447,11 +164417,16 @@ struct HiddenIndexInfo { int eDistinct; /* Value to return from sqlite3_vtab_distinct() */ u32 mIn; /* Mask of terms that are IN (...) */ u32 mHandleIn; /* Terms that vtab will handle as IN (...) */ - sqlite3_value *aRhs[1]; /* RHS values for constraints. MUST BE LAST - ** because extra space is allocated to hold up - ** to nTerm such values */ + sqlite3_value *aRhs[FLEXARRAY]; /* RHS values for constraints. MUST BE LAST + ** Extra space is allocated to hold up + ** to nTerm such values */ }; +/* Size (in bytes) of a HiddenIndeInfo object sufficient to hold as +** many as N constraints */ +#define SZ_HIDDENINDEXINFO(N) \ + (offsetof(HiddenIndexInfo,aRhs) + (N)*sizeof(sqlite3_value*)) + /* Forward declaration of methods */ static int whereLoopResize(sqlite3*, WhereLoop*, int); @@ -164516,6 +165491,8 @@ static SQLITE_NOINLINE void constructAutomaticIndex( } /* Construct the Index object to describe this index */ + assert( nKeyCol <= pTable->nCol + MAX(0, pTable->nCol - BMS + 1) ); + /* ^-- This guarantees that the number of index columns will fit in the u16 */ pIdx = sqlite3AllocateIndexObject(pParse->db, nKeyCol+HasRowid(pTable), 0, &zNotUsed); if( pIdx==0 ) goto end_auto_index_create; @@ -164927,8 +165904,8 @@ static sqlite3_index_info *allocateIndexInfo( */ pIdxInfo = sqlite3DbMallocZero(pParse->db, sizeof(*pIdxInfo) + (sizeof(*pIdxCons) + sizeof(*pUsage))*nTerm - + sizeof(*pIdxOrderBy)*nOrderBy + sizeof(*pHidden) - + sizeof(sqlite3_value*)*nTerm ); + + sizeof(*pIdxOrderBy)*nOrderBy + + SZ_HIDDENINDEXINFO(nTerm) ); if( pIdxInfo==0 ){ sqlite3ErrorMsg(pParse, "out of memory"); return 0; @@ -166564,11 +167541,8 @@ static int whereLoopAddBtreeIndex( assert( pNew->u.btree.nBtm==0 ); opMask = WO_EQ|WO_IN|WO_GT|WO_GE|WO_LT|WO_LE|WO_ISNULL|WO_IS; } - if( pProbe->bUnordered || pProbe->bLowQual ){ - if( pProbe->bUnordered ) opMask &= ~(WO_GT|WO_GE|WO_LT|WO_LE); - if( pProbe->bLowQual && pSrc->fg.isIndexedBy==0 ){ - opMask &= ~(WO_EQ|WO_IN|WO_IS); - } + if( pProbe->bUnordered ){ + opMask &= ~(WO_GT|WO_GE|WO_LT|WO_LE); } assert( pNew->u.btree.nEqnColumn ); @@ -166881,7 +167855,7 @@ static int whereLoopAddBtreeIndex( if( (pNew->wsFlags & WHERE_TOP_LIMIT)==0 && pNew->u.btree.nEqnColumn && (pNew->u.btree.nEqnKeyCol || - pProbe->idxType!=SQLITE_IDXTYPE_PRIMARYKEY) + (pProbe->idxType!=SQLITE_IDXTYPE_PRIMARYKEY && !pProbe->bIdxRowid)) ){ if( pNew->u.btree.nEq>3 ){ sqlite3ProgressCheck(pParse); @@ -167010,6 +167984,7 @@ static int whereUsablePartialIndex( if( (!ExprHasProperty(pExpr, EP_OuterON) || pExpr->w.iJoin==iTab) && ((jointype & JT_OUTER)==0 || ExprHasProperty(pExpr, EP_OuterON)) && sqlite3ExprImpliesExpr(pParse, pExpr, pWhere, iTab) + && !sqlite3ExprImpliesExpr(pParse, pExpr, pWhere, -1) && (pTerm->wtFlags & TERM_VNULL)==0 ){ return 1; @@ -167505,7 +168480,7 @@ static int whereLoopAddBtree( && (HasRowid(pTab) || pWInfo->pSelect!=0 || sqlite3FaultSim(700)) ){ WHERETRACE(0x200, - ("-> %s a covering index according to bitmasks\n", + ("-> %s is a covering index according to bitmasks\n", pProbe->zName, m==0 ? "is" : "is not")); pNew->wsFlags = WHERE_IDX_ONLY | WHERE_INDEXED; } @@ -170122,10 +171097,7 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin( ** field (type Bitmask) it must be aligned on an 8-byte boundary on ** some architectures. Hence the ROUND8() below. */ - nByteWInfo = ROUND8P(sizeof(WhereInfo)); - if( nTabList>1 ){ - nByteWInfo = ROUND8P(nByteWInfo + (nTabList-1)*sizeof(WhereLevel)); - } + nByteWInfo = SZ_WHEREINFO(nTabList); pWInfo = sqlite3DbMallocRawNN(db, nByteWInfo + sizeof(WhereLoop)); if( db->mallocFailed ){ sqlite3DbFree(db, pWInfo); @@ -170342,7 +171314,8 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin( } /* TUNING: Assume that a DISTINCT clause on a subquery reduces - ** the output size by a factor of 8 (LogEst -30). + ** the output size by a factor of 8 (LogEst -30). Search for + ** tag-20250414a to see other cases. */ if( (pWInfo->wctrlFlags & WHERE_WANT_DISTINCT)!=0 ){ WHERETRACE(0x0080,("nRowOut reduced from %d to %d due to DISTINCT\n", @@ -172077,7 +173050,7 @@ SQLITE_PRIVATE int sqlite3WindowRewrite(Parse *pParse, Select *p){ p->pWhere = 0; p->pGroupBy = 0; p->pHaving = 0; - p->selFlags &= ~SF_Aggregate; + p->selFlags &= ~(u32)SF_Aggregate; p->selFlags |= SF_WinRewrite; /* Create the ORDER BY clause for the sub-select. This is the concatenation @@ -174217,6 +175190,11 @@ SQLITE_PRIVATE void sqlite3WindowCodeStep( /* #include "sqliteInt.h" */ +/* +** Verify that the pParse->isCreate field is set +*/ +#define ASSERT_IS_CREATE assert(pParse->isCreate) + /* ** Disable all error recovery processing in the parser push-down ** automaton. @@ -174280,6 +175258,10 @@ static void parserSyntaxError(Parse *pParse, Token *p){ static void disableLookaside(Parse *pParse){ sqlite3 *db = pParse->db; pParse->disableLookaside++; +#ifdef SQLITE_DEBUG + pParse->isCreate = 1; +#endif + memset(&pParse->u1.cr, 0, sizeof(pParse->u1.cr)); DisableLookaside; } @@ -177916,7 +178898,9 @@ static YYACTIONTYPE yy_reduce( } break; case 14: /* createkw ::= CREATE */ -{disableLookaside(pParse);} +{ + disableLookaside(pParse); +} break; case 15: /* ifnotexists ::= */ case 18: /* temp ::= */ yytestcase(yyruleno==18); @@ -178008,7 +178992,7 @@ static YYACTIONTYPE yy_reduce( break; case 32: /* ccons ::= CONSTRAINT nm */ case 67: /* tcons ::= CONSTRAINT nm */ yytestcase(yyruleno==67); -{pParse->constraintName = yymsp[0].minor.yy0;} +{ASSERT_IS_CREATE; pParse->u1.cr.constraintName = yymsp[0].minor.yy0;} break; case 33: /* ccons ::= DEFAULT scantok term */ {sqlite3AddDefaultValue(pParse,yymsp[0].minor.yy590,yymsp[-1].minor.yy0.z,&yymsp[-1].minor.yy0.z[yymsp[-1].minor.yy0.n]);} @@ -178118,7 +179102,7 @@ static YYACTIONTYPE yy_reduce( {yymsp[-1].minor.yy502 = 0;} break; case 66: /* tconscomma ::= COMMA */ -{pParse->constraintName.n = 0;} +{ASSERT_IS_CREATE; pParse->u1.cr.constraintName.n = 0;} break; case 68: /* tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf */ {sqlite3AddPrimaryKey(pParse,yymsp[-3].minor.yy402,yymsp[0].minor.yy502,yymsp[-2].minor.yy502,0);} @@ -178205,8 +179189,8 @@ static YYACTIONTYPE yy_reduce( if( pRhs ){ pRhs->op = (u8)yymsp[-1].minor.yy502; pRhs->pPrior = pLhs; - if( ALWAYS(pLhs) ) pLhs->selFlags &= ~SF_MultiValue; - pRhs->selFlags &= ~SF_MultiValue; + if( ALWAYS(pLhs) ) pLhs->selFlags &= ~(u32)SF_MultiValue; + pRhs->selFlags &= ~(u32)SF_MultiValue; if( yymsp[-1].minor.yy502!=TK_ALL ) pParse->hasCompound = 1; }else{ sqlite3SelectDelete(pParse->db, pLhs); @@ -179011,6 +179995,10 @@ static YYACTIONTYPE yy_reduce( { sqlite3BeginTrigger(pParse, &yymsp[-7].minor.yy0, &yymsp[-6].minor.yy0, yymsp[-5].minor.yy502, yymsp[-4].minor.yy28.a, yymsp[-4].minor.yy28.b, yymsp[-2].minor.yy563, yymsp[0].minor.yy590, yymsp[-10].minor.yy502, yymsp[-8].minor.yy502); yymsp[-10].minor.yy0 = (yymsp[-6].minor.yy0.n==0?yymsp[-7].minor.yy0:yymsp[-6].minor.yy0); /*A-overwrites-T*/ +#ifdef SQLITE_DEBUG + assert( pParse->isCreate ); /* Set by createkw reduce action */ + pParse->isCreate = 0; /* But, should not be set for CREATE TRIGGER */ +#endif } break; case 262: /* trigger_time ::= BEFORE|AFTER */ @@ -180946,7 +181934,11 @@ SQLITE_PRIVATE int sqlite3RunParser(Parse *pParse, const char *zSql){ assert( n==6 ); tokenType = analyzeFilterKeyword((const u8*)&zSql[6], lastTokenParsed); #endif /* SQLITE_OMIT_WINDOWFUNC */ - }else if( tokenType==TK_COMMENT && (db->flags & SQLITE_Comments)!=0 ){ + }else if( tokenType==TK_COMMENT + && (db->init.busy || (db->flags & SQLITE_Comments)!=0) + ){ + /* Ignore SQL comments if either (1) we are reparsing the schema or + ** (2) SQLITE_DBCONFIG_ENABLE_COMMENTS is turned on (the default). */ zSql += n; continue; }else if( tokenType!=TK_QNUMBER ){ @@ -181841,6 +182833,14 @@ SQLITE_API int sqlite3_initialize(void){ if( rc==SQLITE_OK ){ sqlite3PCacheBufferSetup( sqlite3GlobalConfig.pPage, sqlite3GlobalConfig.szPage, sqlite3GlobalConfig.nPage); +#ifdef SQLITE_EXTRA_INIT_MUTEXED + { + int SQLITE_EXTRA_INIT_MUTEXED(const char*); + rc = SQLITE_EXTRA_INIT_MUTEXED(0); + } +#endif + } + if( rc==SQLITE_OK ){ sqlite3MemoryBarrier(); sqlite3GlobalConfig.isInit = 1; #ifdef SQLITE_EXTRA_INIT @@ -182297,17 +183297,22 @@ SQLITE_API int sqlite3_config(int op, ...){ ** If lookaside is already active, return SQLITE_BUSY. ** ** The sz parameter is the number of bytes in each lookaside slot. -** The cnt parameter is the number of slots. If pStart is NULL the -** space for the lookaside memory is obtained from sqlite3_malloc(). -** If pStart is not NULL then it is sz*cnt bytes of memory to use for -** the lookaside memory. +** The cnt parameter is the number of slots. If pBuf is NULL the +** space for the lookaside memory is obtained from sqlite3_malloc() +** or similar. If pBuf is not NULL then it is sz*cnt bytes of memory +** to use for the lookaside memory. */ -static int setupLookaside(sqlite3 *db, void *pBuf, int sz, int cnt){ +static int setupLookaside( + sqlite3 *db, /* Database connection being configured */ + void *pBuf, /* Memory to use for lookaside. May be NULL */ + int sz, /* Desired size of each lookaside memory slot */ + int cnt /* Number of slots to allocate */ +){ #ifndef SQLITE_OMIT_LOOKASIDE - void *pStart; - sqlite3_int64 szAlloc; - int nBig; /* Number of full-size slots */ - int nSm; /* Number smaller LOOKASIDE_SMALL-byte slots */ + void *pStart; /* Start of the lookaside buffer */ + sqlite3_int64 szAlloc; /* Total space set aside for lookaside memory */ + int nBig; /* Number of full-size slots */ + int nSm; /* Number smaller LOOKASIDE_SMALL-byte slots */ if( sqlite3LookasideUsed(db,0)>0 ){ return SQLITE_BUSY; @@ -182320,19 +183325,22 @@ static int setupLookaside(sqlite3 *db, void *pBuf, int sz, int cnt){ sqlite3_free(db->lookaside.pStart); } /* The size of a lookaside slot after ROUNDDOWN8 needs to be larger - ** than a pointer to be useful. + ** than a pointer and small enough to fit in a u16. */ - sz = ROUNDDOWN8(sz); /* IMP: R-33038-09382 */ + sz = ROUNDDOWN8(sz); if( sz<=(int)sizeof(LookasideSlot*) ) sz = 0; if( sz>65528 ) sz = 65528; - if( cnt<0 ) cnt = 0; + /* Count must be at least 1 to be useful, but not so large as to use + ** more than 0x7fff0000 total bytes for lookaside. */ + if( cnt<1 ) cnt = 0; + if( sz>0 && cnt>(0x7fff0000/sz) ) cnt = 0x7fff0000/sz; szAlloc = (i64)sz*(i64)cnt; - if( sz==0 || cnt==0 ){ + if( szAlloc==0 ){ sz = 0; pStart = 0; }else if( pBuf==0 ){ sqlite3BeginBenignMalloc(); - pStart = sqlite3Malloc( szAlloc ); /* IMP: R-61949-35727 */ + pStart = sqlite3Malloc( szAlloc ); sqlite3EndBenignMalloc(); if( pStart ) szAlloc = sqlite3MallocSize(pStart); }else{ @@ -183309,6 +184317,9 @@ SQLITE_API int sqlite3_busy_handler( db->busyHandler.pBusyArg = pArg; db->busyHandler.nBusy = 0; db->busyTimeout = 0; +#ifdef SQLITE_ENABLE_SETLK_TIMEOUT + db->setlkTimeout = 0; +#endif sqlite3_mutex_leave(db->mutex); return SQLITE_OK; } @@ -183358,12 +184369,47 @@ SQLITE_API int sqlite3_busy_timeout(sqlite3 *db, int ms){ sqlite3_busy_handler(db, (int(*)(void*,int))sqliteDefaultBusyCallback, (void*)db); db->busyTimeout = ms; +#ifdef SQLITE_ENABLE_SETLK_TIMEOUT + db->setlkTimeout = ms; +#endif }else{ sqlite3_busy_handler(db, 0, 0); } return SQLITE_OK; } +/* +** Set the setlk timeout value. +*/ +SQLITE_API int sqlite3_setlk_timeout(sqlite3 *db, int ms, int flags){ +#ifdef SQLITE_ENABLE_SETLK_TIMEOUT + int iDb; + int bBOC = ((flags & SQLITE_SETLK_BLOCK_ON_CONNECT) ? 1 : 0); +#endif +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; +#endif + if( ms<-1 ) return SQLITE_RANGE; +#ifdef SQLITE_ENABLE_SETLK_TIMEOUT + db->setlkTimeout = ms; + db->setlkFlags = flags; + sqlite3BtreeEnterAll(db); + for(iDb=0; iDbnDb; iDb++){ + Btree *pBt = db->aDb[iDb].pBt; + if( pBt ){ + sqlite3_file *fd = sqlite3PagerFile(sqlite3BtreePager(pBt)); + sqlite3OsFileControlHint(fd, SQLITE_FCNTL_BLOCK_ON_CONNECT, (void*)&bBOC); + } + } + sqlite3BtreeLeaveAll(db); +#endif +#if !defined(SQLITE_ENABLE_API_ARMOR) && !defined(SQLITE_ENABLE_SETLK_TIMEOUT) + UNUSED_PARAMETER(db); + UNUSED_PARAMETER(flags); +#endif + return SQLITE_OK; +} + /* ** Cause any pending operation to stop at its earliest opportunity. */ @@ -185329,7 +186375,7 @@ SQLITE_API int sqlite3_set_clientdata( return SQLITE_OK; }else{ size_t n = strlen(zName); - p = sqlite3_malloc64( sizeof(DbClientData)+n+1 ); + p = sqlite3_malloc64( SZ_DBCLIENTDATA(n+1) ); if( p==0 ){ if( xDestructor ) xDestructor(pData); sqlite3_mutex_leave(db->mutex); @@ -185483,13 +186529,10 @@ SQLITE_API int sqlite3_table_column_metadata( if( zColumnName==0 ){ /* Query for existence of table only */ }else{ - for(iCol=0; iColnCol; iCol++){ + iCol = sqlite3ColumnIndex(pTab, zColumnName); + if( iCol>=0 ){ pCol = &pTab->aCol[iCol]; - if( 0==sqlite3StrICmp(pCol->zCnName, zColumnName) ){ - break; - } - } - if( iCol==pTab->nCol ){ + }else{ if( HasRowid(pTab) && sqlite3IsRowid(zColumnName) ){ iCol = pTab->iPKey; pCol = iCol>=0 ? &pTab->aCol[iCol] : 0; @@ -185698,8 +186741,8 @@ SQLITE_API int sqlite3_test_control(int op, ...){ /* sqlite3_test_control(SQLITE_TESTCTRL_FK_NO_ACTION, sqlite3 *db, int b); ** ** If b is true, then activate the SQLITE_FkNoAction setting. If b is - ** false then clearn that setting. If the SQLITE_FkNoAction setting is - ** abled, all foreign key ON DELETE and ON UPDATE actions behave as if + ** false then clear that setting. If the SQLITE_FkNoAction setting is + ** enabled, all foreign key ON DELETE and ON UPDATE actions behave as if ** they were NO ACTION, regardless of how they are defined. ** ** NB: One must usually run "PRAGMA writable_schema=RESET" after @@ -187046,7 +188089,7 @@ SQLITE_PRIVATE void sqlite3ConnectionClosed(sqlite3 *db){ ** Here, array { X } means zero or more occurrences of X, adjacent in ** memory. A "position" is an index of a token in the token stream ** generated by the tokenizer. Note that POS_END and POS_COLUMN occur -** in the same logical place as the position element, and act as sentinals +** in the same logical place as the position element, and act as sentinels ** ending a position list array. POS_END is 0. POS_COLUMN is 1. ** The positions numbers are not stored literally but rather as two more ** than the difference from the prior position, or the just the position plus @@ -187265,6 +188308,13 @@ SQLITE_PRIVATE void sqlite3ConnectionClosed(sqlite3 *db){ #ifndef _FTSINT_H #define _FTSINT_H +/* #include */ +/* #include */ +/* #include */ +/* #include */ +/* #include */ +/* #include */ + #if !defined(NDEBUG) && !defined(SQLITE_DEBUG) # define NDEBUG 1 #endif @@ -187734,6 +188784,19 @@ typedef sqlite3_int64 i64; /* 8-byte signed integer */ #define deliberate_fall_through +/* +** Macros needed to provide flexible arrays in a portable way +*/ +#ifndef offsetof +# define offsetof(STRUCTURE,FIELD) ((size_t)((char*)&((STRUCTURE*)0)->FIELD)) +#endif +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) +# define FLEXARRAY +#else +# define FLEXARRAY 1 +#endif + + #endif /* SQLITE_AMALGAMATION */ #ifdef SQLITE_DEBUG @@ -187838,7 +188901,7 @@ struct Fts3Table { #endif #if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) - /* True to disable the incremental doclist optimization. This is controled + /* True to disable the incremental doclist optimization. This is controlled ** by special insert command 'test-no-incr-doclist'. */ int bNoIncrDoclist; @@ -187890,7 +188953,7 @@ struct Fts3Cursor { /* ** The Fts3Cursor.eSearch member is always set to one of the following. -** Actualy, Fts3Cursor.eSearch can be greater than or equal to +** Actually, Fts3Cursor.eSearch can be greater than or equal to ** FTS3_FULLTEXT_SEARCH. If so, then Fts3Cursor.eSearch - 2 is the index ** of the column to be searched. For example, in ** @@ -187963,9 +189026,13 @@ struct Fts3Phrase { */ int nToken; /* Number of tokens in the phrase */ int iColumn; /* Index of column this phrase must match */ - Fts3PhraseToken aToken[1]; /* One entry for each token in the phrase */ + Fts3PhraseToken aToken[FLEXARRAY]; /* One for each token in the phrase */ }; +/* Size (in bytes) of an Fts3Phrase object large enough to hold N tokens */ +#define SZ_FTS3PHRASE(N) \ + (offsetof(Fts3Phrase,aToken)+(N)*sizeof(Fts3PhraseToken)) + /* ** A tree of these objects forms the RHS of a MATCH operator. ** @@ -188199,12 +189266,6 @@ SQLITE_PRIVATE int sqlite3Fts3IntegrityCheck(Fts3Table *p, int *pbOk); # define SQLITE_CORE 1 #endif -/* #include */ -/* #include */ -/* #include */ -/* #include */ -/* #include */ -/* #include */ /* #include "fts3.h" */ #ifndef SQLITE_CORE @@ -190543,7 +191604,7 @@ static int fts3DoclistOrMerge( ** sizes of the two inputs, plus enough space for exactly one of the input ** docids to grow. ** - ** A symetric argument may be made if the doclists are in descending + ** A symmetric argument may be made if the doclists are in descending ** order. */ aOut = sqlite3_malloc64((i64)n1+n2+FTS3_VARINT_MAX-1+FTS3_BUFFER_PADDING); @@ -192342,7 +193403,7 @@ static int fts3EvalDeferredPhrase(Fts3Cursor *pCsr, Fts3Phrase *pPhrase){ nDistance = iPrev - nMaxUndeferred; } - aOut = (char *)sqlite3Fts3MallocZero(nPoslist+FTS3_BUFFER_PADDING); + aOut = (char *)sqlite3Fts3MallocZero(((i64)nPoslist)+FTS3_BUFFER_PADDING); if( !aOut ){ sqlite3_free(aPoslist); return SQLITE_NOMEM; @@ -192641,7 +193702,7 @@ static int incrPhraseTokenNext( ** ** * does not contain any deferred tokens. ** -** Advance it to the next matching documnent in the database and populate +** Advance it to the next matching document in the database and populate ** the Fts3Doclist.pList and nList fields. ** ** If there is no "next" entry and no error occurs, then *pbEof is set to @@ -193648,7 +194709,7 @@ static int fts3EvalNext(Fts3Cursor *pCsr){ } /* -** Restart interation for expression pExpr so that the next call to +** Restart iteration for expression pExpr so that the next call to ** fts3EvalNext() visits the first row. Do not allow incremental ** loading or merging of phrase doclists for this iteration. ** @@ -194840,6 +195901,23 @@ SQLITE_PRIVATE int sqlite3Fts3OpenTokenizer( */ static int fts3ExprParse(ParseContext *, const char *, int, Fts3Expr **, int *); +/* +** Search buffer z[], size n, for a '"' character. Or, if enable_parenthesis +** is defined, search for '(' and ')' as well. Return the index of the first +** such character in the buffer. If there is no such character, return -1. +*/ +static int findBarredChar(const char *z, int n){ + int ii; + for(ii=0; iiiLangid, z, i, &pCursor); + *pnConsumed = n; + rc = sqlite3Fts3OpenTokenizer(pTokenizer, pParse->iLangid, z, n, &pCursor); if( rc==SQLITE_OK ){ const char *zToken; int nToken = 0, iStart = 0, iEnd = 0, iPosition = 0; @@ -194881,7 +195952,18 @@ static int getNextToken( rc = pModule->xNext(pCursor, &zToken, &nToken, &iStart, &iEnd, &iPosition); if( rc==SQLITE_OK ){ - nByte = sizeof(Fts3Expr) + sizeof(Fts3Phrase) + nToken; + /* Check that this tokenization did not gobble up any " characters. Or, + ** if enable_parenthesis is true, that it did not gobble up any + ** open or close parenthesis characters either. If it did, call + ** getNextToken() again, but pass only that part of the input buffer + ** up to the first such character. */ + int iBarred = findBarredChar(z, iEnd); + if( iBarred>=0 ){ + pModule->xClose(pCursor); + return getNextToken(pParse, iCol, z, iBarred, ppExpr, pnConsumed); + } + + nByte = sizeof(Fts3Expr) + SZ_FTS3PHRASE(1) + nToken; pRet = (Fts3Expr *)sqlite3Fts3MallocZero(nByte); if( !pRet ){ rc = SQLITE_NOMEM; @@ -194891,7 +195973,7 @@ static int getNextToken( pRet->pPhrase->nToken = 1; pRet->pPhrase->iColumn = iCol; pRet->pPhrase->aToken[0].n = nToken; - pRet->pPhrase->aToken[0].z = (char *)&pRet->pPhrase[1]; + pRet->pPhrase->aToken[0].z = (char*)&pRet->pPhrase->aToken[1]; memcpy(pRet->pPhrase->aToken[0].z, zToken, nToken); if( iEnd=0 ){ + *pnConsumed = iBarred; + } rc = SQLITE_OK; } @@ -194962,9 +196048,9 @@ static int getNextString( Fts3Expr *p = 0; sqlite3_tokenizer_cursor *pCursor = 0; char *zTemp = 0; - int nTemp = 0; + i64 nTemp = 0; - const int nSpace = sizeof(Fts3Expr) + sizeof(Fts3Phrase); + const int nSpace = sizeof(Fts3Expr) + SZ_FTS3PHRASE(1); int nToken = 0; /* The final Fts3Expr data structure, including the Fts3Phrase, @@ -195336,7 +196422,7 @@ static int fts3ExprParse( /* The isRequirePhrase variable is set to true if a phrase or ** an expression contained in parenthesis is required. If a - ** binary operator (AND, OR, NOT or NEAR) is encounted when + ** binary operator (AND, OR, NOT or NEAR) is encountered when ** isRequirePhrase is set, this is a syntax error. */ if( !isPhrase && isRequirePhrase ){ @@ -195918,7 +197004,6 @@ static void fts3ExprTestCommon( } if( rc!=SQLITE_OK && rc!=SQLITE_NOMEM ){ - sqlite3Fts3ExprFree(pExpr); sqlite3_result_error(context, "Error parsing expression", -1); }else if( rc==SQLITE_NOMEM || !(zBuf = exprToString(pExpr, 0)) ){ sqlite3_result_error_nomem(context); @@ -196161,7 +197246,7 @@ static void fts3HashInsertElement( } -/* Resize the hash table so that it cantains "new_size" buckets. +/* Resize the hash table so that it contains "new_size" buckets. ** "new_size" must be a power of 2. The hash table might fail ** to resize if sqliteMalloc() fails. ** @@ -196616,7 +197701,7 @@ static int star_oh(const char *z){ /* ** If the word ends with zFrom and xCond() is true for the stem -** of the word that preceeds the zFrom ending, then change the +** of the word that precedes the zFrom ending, then change the ** ending to zTo. ** ** The input word *pz and zFrom are both in reverse order. zTo @@ -198127,7 +199212,7 @@ static int fts3tokFilterMethod( fts3tokResetCursor(pCsr); if( idxNum==1 ){ const char *zByte = (const char *)sqlite3_value_text(apVal[0]); - int nByte = sqlite3_value_bytes(apVal[0]); + sqlite3_int64 nByte = sqlite3_value_bytes(apVal[0]); pCsr->zInput = sqlite3_malloc64(nByte+1); if( pCsr->zInput==0 ){ rc = SQLITE_NOMEM; @@ -202199,7 +203284,7 @@ static int fts3IncrmergePush( ** ** It is assumed that the buffer associated with pNode is already large ** enough to accommodate the new entry. The buffer associated with pPrev -** is extended by this function if requrired. +** is extended by this function if required. ** ** If an error (i.e. OOM condition) occurs, an SQLite error code is ** returned. Otherwise, SQLITE_OK. @@ -203862,7 +204947,7 @@ SQLITE_PRIVATE int sqlite3Fts3DeferToken( /* ** SQLite value pRowid contains the rowid of a row that may or may not be ** present in the FTS3 table. If it is, delete it and adjust the contents -** of subsiduary data structures accordingly. +** of subsidiary data structures accordingly. */ static int fts3DeleteByRowid( Fts3Table *p, @@ -204188,9 +205273,13 @@ struct MatchinfoBuffer { int nElem; int bGlobal; /* Set if global data is loaded */ char *zMatchinfo; - u32 aMatchinfo[1]; + u32 aMI[FLEXARRAY]; }; +/* Size (in bytes) of a MatchinfoBuffer sufficient for N elements */ +#define SZ_MATCHINFOBUFFER(N) \ + (offsetof(MatchinfoBuffer,aMI)+(((N)+1)/2)*sizeof(u64)) + /* ** The snippet() and offsets() functions both return text values. An instance @@ -204215,13 +205304,13 @@ struct StrBuffer { static MatchinfoBuffer *fts3MIBufferNew(size_t nElem, const char *zMatchinfo){ MatchinfoBuffer *pRet; sqlite3_int64 nByte = sizeof(u32) * (2*(sqlite3_int64)nElem + 1) - + sizeof(MatchinfoBuffer); + + SZ_MATCHINFOBUFFER(1); sqlite3_int64 nStr = strlen(zMatchinfo); pRet = sqlite3Fts3MallocZero(nByte + nStr+1); if( pRet ){ - pRet->aMatchinfo[0] = (u8*)(&pRet->aMatchinfo[1]) - (u8*)pRet; - pRet->aMatchinfo[1+nElem] = pRet->aMatchinfo[0] + pRet->aMI[0] = (u8*)(&pRet->aMI[1]) - (u8*)pRet; + pRet->aMI[1+nElem] = pRet->aMI[0] + sizeof(u32)*((int)nElem+1); pRet->nElem = (int)nElem; pRet->zMatchinfo = ((char*)pRet) + nByte; @@ -204235,10 +205324,10 @@ static MatchinfoBuffer *fts3MIBufferNew(size_t nElem, const char *zMatchinfo){ static void fts3MIBufferFree(void *p){ MatchinfoBuffer *pBuf = (MatchinfoBuffer*)((u8*)p - ((u32*)p)[-1]); - assert( (u32*)p==&pBuf->aMatchinfo[1] - || (u32*)p==&pBuf->aMatchinfo[pBuf->nElem+2] + assert( (u32*)p==&pBuf->aMI[1] + || (u32*)p==&pBuf->aMI[pBuf->nElem+2] ); - if( (u32*)p==&pBuf->aMatchinfo[1] ){ + if( (u32*)p==&pBuf->aMI[1] ){ pBuf->aRef[1] = 0; }else{ pBuf->aRef[2] = 0; @@ -204255,18 +205344,18 @@ static void (*fts3MIBufferAlloc(MatchinfoBuffer *p, u32 **paOut))(void*){ if( p->aRef[1]==0 ){ p->aRef[1] = 1; - aOut = &p->aMatchinfo[1]; + aOut = &p->aMI[1]; xRet = fts3MIBufferFree; } else if( p->aRef[2]==0 ){ p->aRef[2] = 1; - aOut = &p->aMatchinfo[p->nElem+2]; + aOut = &p->aMI[p->nElem+2]; xRet = fts3MIBufferFree; }else{ aOut = (u32*)sqlite3_malloc64(p->nElem * sizeof(u32)); if( aOut ){ xRet = sqlite3_free; - if( p->bGlobal ) memcpy(aOut, &p->aMatchinfo[1], p->nElem*sizeof(u32)); + if( p->bGlobal ) memcpy(aOut, &p->aMI[1], p->nElem*sizeof(u32)); } } @@ -204276,7 +205365,7 @@ static void (*fts3MIBufferAlloc(MatchinfoBuffer *p, u32 **paOut))(void*){ static void fts3MIBufferSetGlobal(MatchinfoBuffer *p){ p->bGlobal = 1; - memcpy(&p->aMatchinfo[2+p->nElem], &p->aMatchinfo[1], p->nElem*sizeof(u32)); + memcpy(&p->aMI[2+p->nElem], &p->aMI[1], p->nElem*sizeof(u32)); } /* @@ -204691,7 +205780,7 @@ static int fts3StringAppend( } /* If there is insufficient space allocated at StrBuffer.z, use realloc() - ** to grow the buffer until so that it is big enough to accomadate the + ** to grow the buffer until so that it is big enough to accommodate the ** appended data. */ if( pStr->n+nAppend+1>=pStr->nAlloc ){ @@ -205103,16 +206192,16 @@ static size_t fts3MatchinfoSize(MatchInfo *pInfo, char cArg){ break; case FTS3_MATCHINFO_LHITS: - nVal = pInfo->nCol * pInfo->nPhrase; + nVal = (size_t)pInfo->nCol * pInfo->nPhrase; break; case FTS3_MATCHINFO_LHITS_BM: - nVal = pInfo->nPhrase * ((pInfo->nCol + 31) / 32); + nVal = (size_t)pInfo->nPhrase * ((pInfo->nCol + 31) / 32); break; default: assert( cArg==FTS3_MATCHINFO_HITS ); - nVal = pInfo->nCol * pInfo->nPhrase * 3; + nVal = (size_t)pInfo->nCol * pInfo->nPhrase * 3; break; } @@ -206670,8 +207759,8 @@ SQLITE_PRIVATE int sqlite3FtsUnicodeFold(int c, int eRemoveDiacritic){ ** Beginning with version 3.45.0 (circa 2024-01-01), these routines also ** accept BLOB values that have JSON encoded using a binary representation ** called "JSONB". The name JSONB comes from PostgreSQL, however the on-disk -** format SQLite JSONB is completely different and incompatible with -** PostgreSQL JSONB. +** format for SQLite-JSONB is completely different and incompatible with +** PostgreSQL-JSONB. ** ** Decoding and interpreting JSONB is still O(N) where N is the size of ** the input, the same as text JSON. However, the constant of proportionality @@ -206728,7 +207817,7 @@ SQLITE_PRIVATE int sqlite3FtsUnicodeFold(int c, int eRemoveDiacritic){ ** ** The payload size need not be expressed in its minimal form. For example, ** if the payload size is 10, the size can be expressed in any of 5 different -** ways: (1) (X>>4)==10, (2) (X>>4)==12 following by on 0x0a byte, +** ways: (1) (X>>4)==10, (2) (X>>4)==12 following by one 0x0a byte, ** (3) (X>>4)==13 followed by 0x00 and 0x0a, (4) (X>>4)==14 followed by ** 0x00 0x00 0x00 0x0a, or (5) (X>>4)==15 followed by 7 bytes of 0x00 and ** a single byte of 0x0a. The shorter forms are preferred, of course, but @@ -206738,7 +207827,7 @@ SQLITE_PRIVATE int sqlite3FtsUnicodeFold(int c, int eRemoveDiacritic){ ** the size when it becomes known, resulting in a non-minimal encoding. ** ** The value (X>>4)==15 is not actually used in the current implementation -** (as SQLite is currently unable handle BLOBs larger than about 2GB) +** (as SQLite is currently unable to handle BLOBs larger than about 2GB) ** but is included in the design to allow for future enhancements. ** ** The payload follows the header. NULL, TRUE, and FALSE have no payload and @@ -206798,23 +207887,47 @@ static const char * const jsonbType[] = { ** increase for the text-JSON parser. (Ubuntu14.10 gcc 4.8.4 x64 with -Os). */ static const char jsonIsSpace[] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +#ifdef SQLITE_ASCII +/*0 1 2 3 4 5 6 7 8 9 a b c d e f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, /* 0 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1 */ + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 2 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 3 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 4 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 5 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 6 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 7 */ + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 8 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 9 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* a */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* b */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* c */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* d */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* e */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* f */ +#endif +#ifdef SQLITE_EBCDIC +/*0 1 2 3 4 5 6 7 8 9 a b c d e f */ + 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, /* 0 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1 */ + 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 2 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 3 */ + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 4 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 5 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 6 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 7 */ + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 8 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 9 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* a */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* b */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* c */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* d */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* e */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* f */ +#endif + }; #define jsonIsspace(x) (jsonIsSpace[(unsigned char)x]) @@ -206822,7 +207935,13 @@ static const char jsonIsSpace[] = { ** The set of all space characters recognized by jsonIsspace(). ** Useful as the second argument to strspn(). */ +#ifdef SQLITE_ASCII static const char jsonSpaces[] = "\011\012\015\040"; +#endif +#ifdef SQLITE_EBCDIC +static const char jsonSpaces[] = "\005\045\015\100"; +#endif + /* ** Characters that are special to JSON. Control characters, @@ -206831,23 +207950,46 @@ static const char jsonSpaces[] = "\011\012\015\040"; ** it in the set of special characters. */ static const char jsonIsOk[256] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 +#ifdef SQLITE_ASCII +/*0 1 2 3 4 5 6 7 8 9 a b c d e f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1 */ + 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, /* 2 */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 3 */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 4 */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, /* 5 */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 6 */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 7 */ + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 8 */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 9 */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* a */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* b */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* c */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* d */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* e */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 /* f */ +#endif +#ifdef SQLITE_EBCDIC +/*0 1 2 3 4 5 6 7 8 9 a b c d e f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 2 */ + 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, /* 3 */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 4 */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 5 */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 6 */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, /* 7 */ + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 8 */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 9 */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* a */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* b */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* c */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* d */ + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* e */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 /* f */ +#endif }; /* Objects */ @@ -206992,7 +208134,7 @@ struct JsonParse { ** Forward references **************************************************************************/ static void jsonReturnStringAsBlob(JsonString*); -static int jsonFuncArgMightBeBinary(sqlite3_value *pJson); +static int jsonArgIsJsonb(sqlite3_value *pJson, JsonParse *p); static u32 jsonTranslateBlobToText(const JsonParse*,u32,JsonString*); static void jsonReturnParse(sqlite3_context*,JsonParse*); static JsonParse *jsonParseFuncArg(sqlite3_context*,sqlite3_value*,u32); @@ -207066,7 +208208,7 @@ static int jsonCacheInsert( ** most-recently used entry if it isn't so already. ** ** The JsonParse object returned still belongs to the Cache and might -** be deleted at any moment. If the caller whants the JsonParse to +** be deleted at any moment. If the caller wants the JsonParse to ** linger, it needs to increment the nPJRef reference counter. */ static JsonParse *jsonCacheSearch( @@ -207410,11 +208552,9 @@ static void jsonAppendSqlValue( break; } default: { - if( jsonFuncArgMightBeBinary(pValue) ){ - JsonParse px; - memset(&px, 0, sizeof(px)); - px.aBlob = (u8*)sqlite3_value_blob(pValue); - px.nBlob = sqlite3_value_bytes(pValue); + JsonParse px; + memset(&px, 0, sizeof(px)); + if( jsonArgIsJsonb(pValue, &px) ){ jsonTranslateBlobToText(&px, 0, p); }else if( p->eErr==0 ){ sqlite3_result_error(p->pCtx, "JSON cannot hold BLOB values", -1); @@ -207733,7 +208873,7 @@ static void jsonWrongNumArgs( */ static int jsonBlobExpand(JsonParse *pParse, u32 N){ u8 *aNew; - u32 t; + u64 t; assert( N>pParse->nBlobAlloc ); if( pParse->nBlobAlloc==0 ){ t = 100; @@ -207743,8 +208883,9 @@ static int jsonBlobExpand(JsonParse *pParse, u32 N){ if( tdb, pParse->aBlob, t); if( aNew==0 ){ pParse->oom = 1; return 1; } + assert( t<0x7fffffff ); pParse->aBlob = aNew; - pParse->nBlobAlloc = t; + pParse->nBlobAlloc = (u32)t; return 0; } @@ -207811,7 +208952,7 @@ static SQLITE_NOINLINE void jsonBlobExpandAndAppendNode( } -/* Append an node type byte together with the payload size and +/* Append a node type byte together with the payload size and ** possibly also the payload. ** ** If aPayload is not NULL, then it is a pointer to the payload which @@ -208351,7 +209492,12 @@ static int jsonTranslateTextToBlob(JsonParse *pParse, u32 i){ || c=='n' || c=='r' || c=='t' || (c=='u' && jsonIs4Hex(&z[j+1])) ){ if( opcode==JSONB_TEXT ) opcode = JSONB_TEXTJ; - }else if( c=='\'' || c=='0' || c=='v' || c=='\n' + }else if( c=='\'' || c=='v' || c=='\n' +#ifdef SQLITE_BUG_COMPATIBLE_20250510 + || (c=='0') /* Legacy bug compatible */ +#else + || (c=='0' && !sqlite3Isdigit(z[j+1])) /* Correct implementation */ +#endif || (0xe2==(u8)c && 0x80==(u8)z[j+1] && (0xa8==(u8)z[j+2] || 0xa9==(u8)z[j+2])) || (c=='x' && jsonIs2Hex(&z[j+1])) ){ @@ -208701,10 +209847,7 @@ static u32 jsonbPayloadSize(const JsonParse *pParse, u32 i, u32 *pSz){ u8 x; u32 sz; u32 n; - if( NEVER(i>pParse->nBlob) ){ - *pSz = 0; - return 0; - } + assert( i<=pParse->nBlob ); x = pParse->aBlob[i]>>4; if( x<=11 ){ sz = x; @@ -208741,15 +209884,15 @@ static u32 jsonbPayloadSize(const JsonParse *pParse, u32 i, u32 *pSz){ *pSz = 0; return 0; } - sz = (pParse->aBlob[i+5]<<24) + (pParse->aBlob[i+6]<<16) + + sz = ((u32)pParse->aBlob[i+5]<<24) + (pParse->aBlob[i+6]<<16) + (pParse->aBlob[i+7]<<8) + pParse->aBlob[i+8]; n = 9; } if( (i64)i+sz+n > pParse->nBlob && (i64)i+sz+n > pParse->nBlob-pParse->delta ){ - sz = 0; - n = 0; + *pSz = 0; + return 0; } *pSz = sz; return n; @@ -208846,9 +209989,12 @@ static u32 jsonTranslateBlobToText( } case JSONB_TEXT: case JSONB_TEXTJ: { - jsonAppendChar(pOut, '"'); - jsonAppendRaw(pOut, (const char*)&pParse->aBlob[i+n], sz); - jsonAppendChar(pOut, '"'); + if( pOut->nUsed+sz+2<=pOut->nAlloc || jsonStringGrow(pOut, sz+2)==0 ){ + pOut->zBuf[pOut->nUsed] = '"'; + memcpy(pOut->zBuf+pOut->nUsed+1,(const char*)&pParse->aBlob[i+n],sz); + pOut->zBuf[pOut->nUsed+sz+1] = '"'; + pOut->nUsed += sz+2; + } break; } case JSONB_TEXT5: { @@ -209087,33 +210233,6 @@ static u32 jsonTranslateBlobToPrettyText( return i; } - -/* Return true if the input pJson -** -** For performance reasons, this routine does not do a detailed check of the -** input BLOB to ensure that it is well-formed. Hence, false positives are -** possible. False negatives should never occur, however. -*/ -static int jsonFuncArgMightBeBinary(sqlite3_value *pJson){ - u32 sz, n; - const u8 *aBlob; - int nBlob; - JsonParse s; - if( sqlite3_value_type(pJson)!=SQLITE_BLOB ) return 0; - aBlob = sqlite3_value_blob(pJson); - nBlob = sqlite3_value_bytes(pJson); - if( nBlob<1 ) return 0; - if( NEVER(aBlob==0) || (aBlob[0] & 0x0f)>JSONB_OBJECT ) return 0; - memset(&s, 0, sizeof(s)); - s.aBlob = (u8*)aBlob; - s.nBlob = nBlob; - n = jsonbPayloadSize(&s, 0, &sz); - if( n==0 ) return 0; - if( sz+n!=(u32)nBlob ) return 0; - if( (aBlob[0] & 0x0f)<=JSONB_FALSE && sz>0 ) return 0; - return sz+n==(u32)nBlob; -} - /* ** Given that a JSONB_ARRAY object starts at offset i, return ** the number of entries in that array. @@ -209146,6 +210265,82 @@ static void jsonAfterEditSizeAdjust(JsonParse *pParse, u32 iRoot){ pParse->delta += jsonBlobChangePayloadSize(pParse, iRoot, sz); } +/* +** If the JSONB at aIns[0..nIns-1] can be expanded (by denormalizing the +** size field) by d bytes, then write the expansion into aOut[] and +** return true. In this way, an overwrite happens without changing the +** size of the JSONB, which reduces memcpy() operations and also make it +** faster and easier to update the B-Tree entry that contains the JSONB +** in the database. +** +** If the expansion of aIns[] by d bytes cannot be (easily) accomplished +** then return false. +** +** The d parameter is guaranteed to be between 1 and 8. +** +** This routine is an optimization. A correct answer is obtained if it +** always leaves the output unchanged and returns false. +*/ +static int jsonBlobOverwrite( + u8 *aOut, /* Overwrite here */ + const u8 *aIns, /* New content */ + u32 nIns, /* Bytes of new content */ + u32 d /* Need to expand new content by this much */ +){ + u32 szPayload; /* Bytes of payload */ + u32 i; /* New header size, after expansion & a loop counter */ + u8 szHdr; /* Size of header before expansion */ + + /* Lookup table for finding the upper 4 bits of the first byte of the + ** expanded aIns[], based on the size of the expanded aIns[] header: + ** + ** 2 3 4 5 6 7 8 9 */ + static const u8 aType[] = { 0xc0, 0xd0, 0, 0xe0, 0, 0, 0, 0xf0 }; + + if( (aIns[0]&0x0f)<=2 ) return 0; /* Cannot enlarge NULL, true, false */ + switch( aIns[0]>>4 ){ + default: { /* aIns[] header size 1 */ + if( ((1<=2 && i<=9 && aType[i-2]!=0 ); + aOut[0] = (aIns[0] & 0x0f) | aType[i-2]; + memcpy(&aOut[i], &aIns[szHdr], nIns-szHdr); + szPayload = nIns - szHdr; + while( 1/*edit-by-break*/ ){ + i--; + aOut[i] = szPayload & 0xff; + if( i==1 ) break; + szPayload >>= 8; + } + assert( (szPayload>>8)==0 ); + return 1; +} + /* ** Modify the JSONB blob at pParse->aBlob by removing nDel bytes of ** content beginning at iDel, and replacing them with nIns bytes of @@ -209167,6 +210362,11 @@ static void jsonBlobEdit( u32 nIns /* Bytes of content to insert */ ){ i64 d = (i64)nIns - (i64)nDel; + if( d<0 && d>=(-8) && aIns!=0 + && jsonBlobOverwrite(&pParse->aBlob[iDel], aIns, nIns, (int)-d) + ){ + return; + } if( d!=0 ){ if( pParse->nBlob + d > pParse->nBlobAlloc ){ jsonBlobExpand(pParse, pParse->nBlob+d); @@ -209178,7 +210378,9 @@ static void jsonBlobEdit( pParse->nBlob += d; pParse->delta += d; } - if( nIns && aIns ) memcpy(&pParse->aBlob[iDel], aIns, nIns); + if( nIns && aIns ){ + memcpy(&pParse->aBlob[iDel], aIns, nIns); + } } /* @@ -209263,7 +210465,21 @@ static u32 jsonUnescapeOneChar(const char *z, u32 n, u32 *piOut){ case 'r': { *piOut = '\r'; return 2; } case 't': { *piOut = '\t'; return 2; } case 'v': { *piOut = '\v'; return 2; } - case '0': { *piOut = 0; return 2; } + case '0': { + /* JSON5 requires that the \0 escape not be followed by a digit. + ** But SQLite did not enforce this restriction in versions 3.42.0 + ** through 3.49.2. That was a bug. But some applications might have + ** come to depend on that bug. Use the SQLITE_BUG_COMPATIBLE_20250510 + ** option to restore the old buggy behavior. */ +#ifdef SQLITE_BUG_COMPATIBLE_20250510 + /* Legacy bug-compatible behavior */ + *piOut = 0; +#else + /* Correct behavior */ + *piOut = (n>2 && sqlite3Isdigit(z[2])) ? JSON_INVALID_CHAR : 0; +#endif + return 2; + } case '\'': case '"': case '/': @@ -209763,7 +210979,7 @@ static void jsonReturnFromBlob( char *zOut; u32 nOut = sz; z = (const char*)&pParse->aBlob[i+n]; - zOut = sqlite3DbMallocRaw(db, nOut+1); + zOut = sqlite3DbMallocRaw(db, ((u64)nOut)+1); if( zOut==0 ) goto returnfromblob_oom; for(iIn=iOut=0; iInaBlob = (u8*)sqlite3_value_blob(pArg); - pParse->nBlob = sqlite3_value_bytes(pArg); - }else{ + if( !jsonArgIsJsonb(pArg, pParse) ){ sqlite3_result_error(ctx, "JSON cannot hold BLOB values", -1); return 1; } @@ -209941,7 +211154,7 @@ static char *jsonBadPathError( } /* argv[0] is a BLOB that seems likely to be a JSONB. Subsequent -** arguments come in parse where each pair contains a JSON path and +** arguments come in pairs where each pair contains a JSON path and ** content to insert or set at that patch. Do the updates ** and return the result. ** @@ -210012,27 +211225,46 @@ static void jsonInsertIntoBlob( /* ** If pArg is a blob that seems like a JSONB blob, then initialize ** p to point to that JSONB and return TRUE. If pArg does not seem like -** a JSONB blob, then return FALSE; -** -** This routine is only called if it is already known that pArg is a -** blob. The only open question is whether or not the blob appears -** to be a JSONB blob. +** a JSONB blob, then return FALSE. +** +** For small BLOBs (having no more than 7 bytes of payload) a full +** validity check is done. So for small BLOBs this routine only returns +** true if the value is guaranteed to be a valid JSONB. For larger BLOBs +** (8 byte or more of payload) only the size of the outermost element is +** checked to verify that the BLOB is superficially valid JSONB. +** +** A full JSONB validation is done on smaller BLOBs because those BLOBs might +** also be text JSON that has been incorrectly cast into a BLOB. +** (See tag-20240123-a and https://sqlite.org/forum/forumpost/012136abd5) +** If the BLOB is 9 bytes are larger, then it is not possible for the +** superficial size check done here to pass if the input is really text +** JSON so we do not need to look deeper in that case. +** +** Why we only need to do full JSONB validation for smaller BLOBs: +** +** The first byte of valid JSON text must be one of: '{', '[', '"', ' ', '\n', +** '\r', '\t', '-', or a digit '0' through '9'. Of these, only a subset +** can also be the first byte of JSONB: '{', '[', and digits '3' +** through '9'. In every one of those cases, the payload size is 7 bytes +** or less. So if we do full JSONB validation for every BLOB where the +** payload is less than 7 bytes, we will never get a false positive for +** JSONB on an input that is really text JSON. */ static int jsonArgIsJsonb(sqlite3_value *pArg, JsonParse *p){ u32 n, sz = 0; + u8 c; + if( sqlite3_value_type(pArg)!=SQLITE_BLOB ) return 0; p->aBlob = (u8*)sqlite3_value_blob(pArg); p->nBlob = (u32)sqlite3_value_bytes(pArg); - if( p->nBlob==0 ){ - p->aBlob = 0; - return 0; - } - if( NEVER(p->aBlob==0) ){ - return 0; - } - if( (p->aBlob[0] & 0x0f)<=JSONB_OBJECT + if( p->nBlob>0 + && ALWAYS(p->aBlob!=0) + && ((c = p->aBlob[0]) & 0x0f)<=JSONB_OBJECT && (n = jsonbPayloadSize(p, 0, &sz))>0 && sz+n==p->nBlob - && ((p->aBlob[0] & 0x0f)>JSONB_FALSE || sz==0) + && ((c & 0x0f)>JSONB_FALSE || sz==0) + && (sz>7 + || (c!=0x7b && c!=0x5b && !sqlite3Isdigit(c)) + || jsonbValidityCheck(p, 0, p->nBlob, 1)==0) ){ return 1; } @@ -210110,7 +211342,7 @@ static JsonParse *jsonParseFuncArg( ** JSON functions were suppose to work. From the beginning, blob was ** reserved for expansion and a blob value should have raised an error. ** But it did not, due to a bug. And many applications came to depend - ** upon this buggy behavior, espeically when using the CLI and reading + ** upon this buggy behavior, especially when using the CLI and reading ** JSON text using readfile(), which returns a blob. For this reason ** we will continue to support the bug moving forward. ** See for example https://sqlite.org/forum/forumpost/012136abd5292b8d @@ -211125,21 +212357,17 @@ static void jsonValidFunc( return; } case SQLITE_BLOB: { - if( jsonFuncArgMightBeBinary(argv[0]) ){ + JsonParse py; + memset(&py, 0, sizeof(py)); + if( jsonArgIsJsonb(argv[0], &py) ){ if( flags & 0x04 ){ /* Superficial checking only - accomplished by the - ** jsonFuncArgMightBeBinary() call above. */ + ** jsonArgIsJsonb() call above. */ res = 1; }else if( flags & 0x08 ){ /* Strict checking. Check by translating BLOB->TEXT->BLOB. If ** no errors occur, call that a "strict check". */ - JsonParse px; - u32 iErr; - memset(&px, 0, sizeof(px)); - px.aBlob = (u8*)sqlite3_value_blob(argv[0]); - px.nBlob = sqlite3_value_bytes(argv[0]); - iErr = jsonbValidityCheck(&px, 0, px.nBlob, 1); - res = iErr==0; + res = 0==jsonbValidityCheck(&py, 0, py.nBlob, 1); } break; } @@ -211197,9 +212425,7 @@ static void jsonErrorFunc( UNUSED_PARAMETER(argc); memset(&s, 0, sizeof(s)); s.db = sqlite3_context_db_handle(ctx); - if( jsonFuncArgMightBeBinary(argv[0]) ){ - s.aBlob = (u8*)sqlite3_value_blob(argv[0]); - s.nBlob = sqlite3_value_bytes(argv[0]); + if( jsonArgIsJsonb(argv[0], &s) ){ iErrPos = (i64)jsonbValidityCheck(&s, 0, s.nBlob, 1); }else{ s.zJson = (char*)sqlite3_value_text(argv[0]); @@ -211360,18 +212586,20 @@ static void jsonObjectStep( UNUSED_PARAMETER(argc); pStr = (JsonString*)sqlite3_aggregate_context(ctx, sizeof(*pStr)); if( pStr ){ + z = (const char*)sqlite3_value_text(argv[0]); + n = sqlite3Strlen30(z); if( pStr->zBuf==0 ){ jsonStringInit(pStr, ctx); jsonAppendChar(pStr, '{'); - }else if( pStr->nUsed>1 ){ + }else if( pStr->nUsed>1 && z!=0 ){ jsonAppendChar(pStr, ','); } pStr->pCtx = ctx; - z = (const char*)sqlite3_value_text(argv[0]); - n = sqlite3Strlen30(z); - jsonAppendString(pStr, z, n); - jsonAppendChar(pStr, ':'); - jsonAppendSqlValue(pStr, argv[1]); + if( z!=0 ){ + jsonAppendString(pStr, z, n); + jsonAppendChar(pStr, ':'); + jsonAppendSqlValue(pStr, argv[1]); + } } } static void jsonObjectCompute(sqlite3_context *ctx, int isFinal){ @@ -211884,9 +213112,8 @@ static int jsonEachFilter( memset(&p->sParse, 0, sizeof(p->sParse)); p->sParse.nJPRef = 1; p->sParse.db = p->db; - if( jsonFuncArgMightBeBinary(argv[0]) ){ - p->sParse.nBlob = sqlite3_value_bytes(argv[0]); - p->sParse.aBlob = (u8*)sqlite3_value_blob(argv[0]); + if( jsonArgIsJsonb(argv[0], &p->sParse) ){ + /* We have JSONB */ }else{ p->sParse.zJson = (char*)sqlite3_value_text(argv[0]); p->sParse.nJson = sqlite3_value_bytes(argv[0]); @@ -212210,6 +213437,14 @@ typedef unsigned int u32; # define ALWAYS(X) (X) # define NEVER(X) (X) #endif +#ifndef offsetof +#define offsetof(STRUCTURE,FIELD) ((size_t)((char*)&((STRUCTURE*)0)->FIELD)) +#endif +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) +# define FLEXARRAY +#else +# define FLEXARRAY 1 +#endif #endif /* !defined(SQLITE_AMALGAMATION) */ /* Macro to check for 4-byte alignment. Only used inside of assert() */ @@ -212530,9 +213765,13 @@ struct RtreeMatchArg { RtreeGeomCallback cb; /* Info about the callback functions */ int nParam; /* Number of parameters to the SQL function */ sqlite3_value **apSqlParam; /* Original SQL parameter values */ - RtreeDValue aParam[1]; /* Values for parameters to the SQL function */ + RtreeDValue aParam[FLEXARRAY]; /* Values for parameters to the SQL function */ }; +/* Size of an RtreeMatchArg object with N parameters */ +#define SZ_RTREEMATCHARG(N) \ + (offsetof(RtreeMatchArg,aParam)+(N)*sizeof(RtreeDValue)) + #ifndef MAX # define MAX(x,y) ((x) < (y) ? (y) : (x)) #endif @@ -214221,7 +215460,7 @@ static int rtreeBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){ } /* -** Return the N-dimensional volumn of the cell stored in *p. +** Return the N-dimensional volume of the cell stored in *p. */ static RtreeDValue cellArea(Rtree *pRtree, RtreeCell *p){ RtreeDValue area = (RtreeDValue)1; @@ -215987,7 +217226,7 @@ static sqlite3_stmt *rtreeCheckPrepare( /* ** The second and subsequent arguments to this function are a printf() ** style format string and arguments. This function formats the string and -** appends it to the report being accumuated in pCheck. +** appends it to the report being accumulated in pCheck. */ static void rtreeCheckAppendMsg(RtreeCheck *pCheck, const char *zFmt, ...){ va_list ap; @@ -217175,7 +218414,7 @@ static void geopolyBBoxFinal( ** Determine if point (x0,y0) is beneath line segment (x1,y1)->(x2,y2). ** Returns: ** -** +2 x0,y0 is on the line segement +** +2 x0,y0 is on the line segment ** ** +1 x0,y0 is beneath line segment ** @@ -217281,7 +218520,7 @@ static void geopolyWithinFunc( sqlite3_free(p2); } -/* Objects used by the overlap algorihm. */ +/* Objects used by the overlap algorithm. */ typedef struct GeoEvent GeoEvent; typedef struct GeoSegment GeoSegment; typedef struct GeoOverlap GeoOverlap; @@ -218328,8 +219567,7 @@ static void geomCallback(sqlite3_context *ctx, int nArg, sqlite3_value **aArg){ sqlite3_int64 nBlob; int memErr = 0; - nBlob = sizeof(RtreeMatchArg) + (nArg-1)*sizeof(RtreeDValue) - + nArg*sizeof(sqlite3_value*); + nBlob = SZ_RTREEMATCHARG(nArg) + nArg*sizeof(sqlite3_value*); pBlob = (RtreeMatchArg *)sqlite3_malloc64(nBlob); if( !pBlob ){ sqlite3_result_error_nomem(ctx); @@ -219424,7 +220662,7 @@ SQLITE_PRIVATE void sqlite3Fts3IcuTokenizerModule( ** ** "RBU" stands for "Resumable Bulk Update". As in a large database update ** transmitted via a wireless network to a mobile device. A transaction -** applied using this extension is hence refered to as an "RBU update". +** applied using this extension is hence referred to as an "RBU update". ** ** ** LIMITATIONS @@ -219721,7 +220959,7 @@ SQLITE_API sqlite3rbu *sqlite3rbu_open( ** the next call to sqlite3rbu_vacuum() opens a handle that starts a ** new RBU vacuum operation. ** -** As with sqlite3rbu_open(), Zipvfs users should rever to the comment +** As with sqlite3rbu_open(), Zipvfs users should refer to the comment ** describing the sqlite3rbu_create_vfs() API function below for ** a description of the complications associated with using RBU with ** zipvfs databases. @@ -219817,7 +221055,7 @@ SQLITE_API int sqlite3rbu_savestate(sqlite3rbu *pRbu); ** ** If the RBU update has been completely applied, mark the RBU database ** as fully applied. Otherwise, assuming no error has occurred, save the -** current state of the RBU update appliation to the RBU database. +** current state of the RBU update application to the RBU database. ** ** If an error has already occurred as part of an sqlite3rbu_step() ** or sqlite3rbu_open() call, or if one occurs within this function, an @@ -224743,7 +225981,7 @@ static int rbuVfsFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){ /* If this is an RBU vacuum operation and this is the target database, ** pretend that it has at least one page. Otherwise, SQLite will not - ** check for the existance of a *-wal file. rbuVfsRead() contains + ** check for the existence of a *-wal file. rbuVfsRead() contains ** similar logic. */ if( rc==SQLITE_OK && *pSize==0 && p->pRbu && rbuIsVacuum(p->pRbu) @@ -226675,8 +227913,8 @@ static int dbpageUpdate( /* "INSERT INTO dbpage($PGNO,NULL)" causes page number $PGNO and ** all subsequent pages to be deleted. */ pTab->iDbTrunc = iDb; - pgno--; - pTab->pgnoTrunc = pgno; + pTab->pgnoTrunc = pgno-1; + pgno = 1; }else{ zErr = "bad page value"; goto update_fail; @@ -227973,7 +229211,7 @@ static int sessionTableInfo( /* ** This function is called to initialize the SessionTable.nCol, azCol[] ** abPK[] and azDflt[] members of SessionTable object pTab. If these -** fields are already initilialized, this function is a no-op. +** fields are already initialized, this function is a no-op. ** ** If an error occurs, an error code is stored in sqlite3_session.rc and ** non-zero returned. Or, if no error occurs but the table has no primary @@ -227992,6 +229230,8 @@ static int sessionInitTable( if( pTab->nCol==0 ){ u8 *abPK; assert( pTab->azCol==0 || pTab->abPK==0 ); + sqlite3_free(pTab->azCol); + pTab->abPK = 0; rc = sessionTableInfo(pSession, db, zDb, pTab->zName, &pTab->nCol, &pTab->nTotalCol, 0, &pTab->azCol, &pTab->azDflt, &pTab->aiIdx, &abPK, @@ -228999,7 +230239,9 @@ SQLITE_API int sqlite3session_diff( SessionTable *pTo; /* Table zTbl */ /* Locate and if necessary initialize the target table object */ + pSession->bAutoAttach++; rc = sessionFindTable(pSession, zTbl, &pTo); + pSession->bAutoAttach--; if( pTo==0 ) goto diff_out; if( sessionInitTable(pSession, pTo, pSession->db, pSession->zDb) ){ rc = pSession->rc; @@ -229010,17 +230252,43 @@ SQLITE_API int sqlite3session_diff( if( rc==SQLITE_OK ){ int bHasPk = 0; int bMismatch = 0; - int nCol; /* Columns in zFrom.zTbl */ + int nCol = 0; /* Columns in zFrom.zTbl */ int bRowid = 0; - u8 *abPK; + u8 *abPK = 0; const char **azCol = 0; - rc = sessionTableInfo(0, db, zFrom, zTbl, - &nCol, 0, 0, &azCol, 0, 0, &abPK, - pSession->bImplicitPK ? &bRowid : 0 - ); + char *zDbExists = 0; + + /* Check that database zFrom is attached. */ + zDbExists = sqlite3_mprintf("SELECT * FROM %Q.sqlite_schema", zFrom); + if( zDbExists==0 ){ + rc = SQLITE_NOMEM; + }else{ + sqlite3_stmt *pDbExists = 0; + rc = sqlite3_prepare_v2(db, zDbExists, -1, &pDbExists, 0); + if( rc==SQLITE_ERROR ){ + rc = SQLITE_OK; + nCol = -1; + } + sqlite3_finalize(pDbExists); + sqlite3_free(zDbExists); + } + + if( rc==SQLITE_OK && nCol==0 ){ + rc = sessionTableInfo(0, db, zFrom, zTbl, + &nCol, 0, 0, &azCol, 0, 0, &abPK, + pSession->bImplicitPK ? &bRowid : 0 + ); + } if( rc==SQLITE_OK ){ if( pTo->nCol!=nCol ){ - bMismatch = 1; + if( nCol<=0 ){ + rc = SQLITE_SCHEMA; + if( pzErrMsg ){ + *pzErrMsg = sqlite3_mprintf("no such table: %s.%s", zFrom, zTbl); + } + }else{ + bMismatch = 1; + } }else{ int i; for(i=0; idb; /* Source database handle */ SessionTable *pTab; /* Used to iterate through attached tables */ - SessionBuffer buf = {0,0,0}; /* Buffer in which to accumlate changeset */ + SessionBuffer buf = {0,0,0}; /* Buffer in which to accumulate changeset */ int rc; /* Return code */ assert( xOutput==0 || (pnChangeset==0 && ppChangeset==0) ); @@ -230149,14 +231417,15 @@ SQLITE_API int sqlite3changeset_start_v2_strm( ** object and the buffer is full, discard some data to free up space. */ static void sessionDiscardData(SessionInput *pIn){ - if( pIn->xInput && pIn->iNext>=sessions_strm_chunk_size ){ - int nMove = pIn->buf.nBuf - pIn->iNext; + if( pIn->xInput && pIn->iCurrent>=sessions_strm_chunk_size ){ + int nMove = pIn->buf.nBuf - pIn->iCurrent; assert( nMove>=0 ); if( nMove>0 ){ - memmove(pIn->buf.aBuf, &pIn->buf.aBuf[pIn->iNext], nMove); + memmove(pIn->buf.aBuf, &pIn->buf.aBuf[pIn->iCurrent], nMove); } - pIn->buf.nBuf -= pIn->iNext; - pIn->iNext = 0; + pIn->buf.nBuf -= pIn->iCurrent; + pIn->iNext -= pIn->iCurrent; + pIn->iCurrent = 0; pIn->nData = pIn->buf.nBuf; } } @@ -230510,8 +231779,8 @@ static int sessionChangesetNextOne( p->rc = sessionInputBuffer(&p->in, 2); if( p->rc!=SQLITE_OK ) return p->rc; - sessionDiscardData(&p->in); p->in.iCurrent = p->in.iNext; + sessionDiscardData(&p->in); /* If the iterator is already at the end of the changeset, return DONE. */ if( p->in.iNext>=p->in.nData ){ @@ -232870,14 +234139,19 @@ SQLITE_API int sqlite3changegroup_add_change( sqlite3_changegroup *pGrp, sqlite3_changeset_iter *pIter ){ + int rc = SQLITE_OK; + if( pIter->in.iCurrent==pIter->in.iNext || pIter->rc!=SQLITE_OK || pIter->bInvert ){ /* Iterator does not point to any valid entry or is an INVERT iterator. */ - return SQLITE_ERROR; + rc = SQLITE_ERROR; + }else{ + pIter->in.bNoDiscard = 1; + rc = sessionOneChangeToHash(pGrp, pIter, 0); } - return sessionOneChangeToHash(pGrp, pIter, 0); + return rc; } /* @@ -234230,6 +235504,18 @@ typedef sqlite3_uint64 u64; # define EIGHT_BYTE_ALIGNMENT(X) ((((uptr)(X) - (uptr)0)&7)==0) #endif +/* +** Macros needed to provide flexible arrays in a portable way +*/ +#ifndef offsetof +# define offsetof(STRUCTURE,FIELD) ((size_t)((char*)&((STRUCTURE*)0)->FIELD)) +#endif +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) +# define FLEXARRAY +#else +# define FLEXARRAY 1 +#endif + #endif /* Truncate very long tokens to this many bytes. Hard limit is @@ -234302,10 +235588,11 @@ typedef struct Fts5Colset Fts5Colset; */ struct Fts5Colset { int nCol; - int aiCol[1]; + int aiCol[FLEXARRAY]; }; - +/* Size (int bytes) of a complete Fts5Colset object with N columns. */ +#define SZ_FTS5COLSET(N) (sizeof(i64)*((N+2)/2)) /************************************************************************** ** Interface to code in fts5_config.c. fts5_config.c contains contains code @@ -235134,7 +236421,7 @@ static void sqlite3Fts5UnicodeAscii(u8*, u8*); ** ** The "lemon" program processes an LALR(1) input grammar file, then uses ** this template to construct a parser. The "lemon" program inserts text -** at each "%%" line. Also, any "P-a-r-s-e" identifer prefix (without the +** at each "%%" line. Also, any "P-a-r-s-e" identifier prefix (without the ** interstitial "-" characters) contained in this template is changed into ** the value of the %name directive from the grammar. Otherwise, the content ** of this template is copied straight through into the generate parser @@ -237288,7 +238575,7 @@ static int fts5Bm25GetData( ** under consideration. ** ** The problem with this is that if (N < 2*nHit), the IDF is - ** negative. Which is undesirable. So the mimimum allowable IDF is + ** negative. Which is undesirable. So the minimum allowable IDF is ** (1e-6) - roughly the same as a term that appears in just over ** half of set of 5,000,000 documents. */ double idf = log( (nRow - nHit + 0.5) / (nHit + 0.5) ); @@ -237751,7 +239038,7 @@ static char *sqlite3Fts5Strndup(int *pRc, const char *pIn, int nIn){ ** * The 52 upper and lower case ASCII characters, and ** * The 10 integer ASCII characters. ** * The underscore character "_" (0x5F). -** * The unicode "subsitute" character (0x1A). +** * The unicode "substitute" character (0x1A). */ static int sqlite3Fts5IsBareword(char t){ u8 aBareword[128] = { @@ -239069,9 +240356,13 @@ struct Fts5ExprNode { /* Child nodes. For a NOT node, this array always contains 2 entries. For ** AND or OR nodes, it contains 2 or more entries. */ int nChild; /* Number of child nodes */ - Fts5ExprNode *apChild[1]; /* Array of child nodes */ + Fts5ExprNode *apChild[FLEXARRAY]; /* Array of child nodes */ }; +/* Size (in bytes) of an Fts5ExprNode object that holds up to N children */ +#define SZ_FTS5EXPRNODE(N) \ + (offsetof(Fts5ExprNode,apChild) + (N)*sizeof(Fts5ExprNode*)) + #define Fts5NodeIsString(p) ((p)->eType==FTS5_TERM || (p)->eType==FTS5_STRING) /* @@ -239102,9 +240393,13 @@ struct Fts5ExprPhrase { Fts5ExprNode *pNode; /* FTS5_STRING node this phrase is part of */ Fts5Buffer poslist; /* Current position list */ int nTerm; /* Number of entries in aTerm[] */ - Fts5ExprTerm aTerm[1]; /* Terms that make up this phrase */ + Fts5ExprTerm aTerm[FLEXARRAY]; /* Terms that make up this phrase */ }; +/* Size (in bytes) of an Fts5ExprPhrase object that holds up to N terms */ +#define SZ_FTS5EXPRPHRASE(N) \ + (offsetof(Fts5ExprPhrase,aTerm) + (N)*sizeof(Fts5ExprTerm)) + /* ** One or more phrases that must appear within a certain token distance of ** each other within each matching document. @@ -239113,9 +240408,12 @@ struct Fts5ExprNearset { int nNear; /* NEAR parameter */ Fts5Colset *pColset; /* Columns to search (NULL -> all columns) */ int nPhrase; /* Number of entries in aPhrase[] array */ - Fts5ExprPhrase *apPhrase[1]; /* Array of phrase pointers */ + Fts5ExprPhrase *apPhrase[FLEXARRAY]; /* Array of phrase pointers */ }; +/* Size (in bytes) of an Fts5ExprNearset object covering up to N phrases */ +#define SZ_FTS5EXPRNEARSET(N) \ + (offsetof(Fts5ExprNearset,apPhrase)+(N)*sizeof(Fts5ExprPhrase*)) /* ** Parse context. @@ -239275,7 +240573,7 @@ static int sqlite3Fts5ExprNew( /* If the LHS of the MATCH expression was a user column, apply the ** implicit column-filter. */ if( sParse.rc==SQLITE_OK && iColnCol ){ - int n = sizeof(Fts5Colset); + int n = SZ_FTS5COLSET(1); Fts5Colset *pColset = (Fts5Colset*)sqlite3Fts5MallocZero(&sParse.rc, n); if( pColset ){ pColset->nCol = 1; @@ -240633,7 +241931,7 @@ static Fts5ExprNearset *sqlite3Fts5ParseNearset( if( pParse->rc==SQLITE_OK ){ if( pNear==0 ){ sqlite3_int64 nByte; - nByte = sizeof(Fts5ExprNearset) + SZALLOC * sizeof(Fts5ExprPhrase*); + nByte = SZ_FTS5EXPRNEARSET(SZALLOC+1); pRet = sqlite3_malloc64(nByte); if( pRet==0 ){ pParse->rc = SQLITE_NOMEM; @@ -240644,7 +241942,7 @@ static Fts5ExprNearset *sqlite3Fts5ParseNearset( int nNew = pNear->nPhrase + SZALLOC; sqlite3_int64 nByte; - nByte = sizeof(Fts5ExprNearset) + nNew * sizeof(Fts5ExprPhrase*); + nByte = SZ_FTS5EXPRNEARSET(nNew+1); pRet = (Fts5ExprNearset*)sqlite3_realloc64(pNear, nByte); if( pRet==0 ){ pParse->rc = SQLITE_NOMEM; @@ -240735,12 +242033,12 @@ static int fts5ParseTokenize( int nNew = SZALLOC + (pPhrase ? pPhrase->nTerm : 0); pNew = (Fts5ExprPhrase*)sqlite3_realloc64(pPhrase, - sizeof(Fts5ExprPhrase) + sizeof(Fts5ExprTerm) * nNew + SZ_FTS5EXPRPHRASE(nNew+1) ); if( pNew==0 ){ rc = SQLITE_NOMEM; }else{ - if( pPhrase==0 ) memset(pNew, 0, sizeof(Fts5ExprPhrase)); + if( pPhrase==0 ) memset(pNew, 0, SZ_FTS5EXPRPHRASE(1)); pCtx->pPhrase = pPhrase = pNew; pNew->nTerm = nNew - SZALLOC; } @@ -240848,7 +242146,7 @@ static Fts5ExprPhrase *sqlite3Fts5ParseTerm( if( sCtx.pPhrase==0 ){ /* This happens when parsing a token or quoted phrase that contains ** no token characters at all. (e.g ... MATCH '""'). */ - sCtx.pPhrase = sqlite3Fts5MallocZero(&pParse->rc, sizeof(Fts5ExprPhrase)); + sCtx.pPhrase = sqlite3Fts5MallocZero(&pParse->rc, SZ_FTS5EXPRPHRASE(1)); }else if( sCtx.pPhrase->nTerm ){ sCtx.pPhrase->aTerm[sCtx.pPhrase->nTerm-1].bPrefix = (u8)bPrefix; } @@ -240883,19 +242181,18 @@ static int sqlite3Fts5ExprClonePhrase( sizeof(Fts5ExprPhrase*)); } if( rc==SQLITE_OK ){ - pNew->pRoot = (Fts5ExprNode*)sqlite3Fts5MallocZero(&rc, - sizeof(Fts5ExprNode)); + pNew->pRoot = (Fts5ExprNode*)sqlite3Fts5MallocZero(&rc, SZ_FTS5EXPRNODE(1)); } if( rc==SQLITE_OK ){ pNew->pRoot->pNear = (Fts5ExprNearset*)sqlite3Fts5MallocZero(&rc, - sizeof(Fts5ExprNearset) + sizeof(Fts5ExprPhrase*)); + SZ_FTS5EXPRNEARSET(2)); } if( rc==SQLITE_OK && ALWAYS(pOrig!=0) ){ Fts5Colset *pColsetOrig = pOrig->pNode->pNear->pColset; if( pColsetOrig ){ sqlite3_int64 nByte; Fts5Colset *pColset; - nByte = sizeof(Fts5Colset) + (pColsetOrig->nCol-1) * sizeof(int); + nByte = SZ_FTS5COLSET(pColsetOrig->nCol); pColset = (Fts5Colset*)sqlite3Fts5MallocZero(&rc, nByte); if( pColset ){ memcpy(pColset, pColsetOrig, (size_t)nByte); @@ -240923,7 +242220,7 @@ static int sqlite3Fts5ExprClonePhrase( }else{ /* This happens when parsing a token or quoted phrase that contains ** no token characters at all. (e.g ... MATCH '""'). */ - sCtx.pPhrase = sqlite3Fts5MallocZero(&rc, sizeof(Fts5ExprPhrase)); + sCtx.pPhrase = sqlite3Fts5MallocZero(&rc, SZ_FTS5EXPRPHRASE(1)); } } @@ -240988,7 +242285,8 @@ static void sqlite3Fts5ParseSetDistance( ); return; } - nNear = nNear * 10 + (p->p[i] - '0'); + if( nNear<214748363 ) nNear = nNear * 10 + (p->p[i] - '0'); + /* ^^^^^^^^^^^^^^^--- Prevent integer overflow */ } }else{ nNear = FTS5_DEFAULT_NEARDIST; @@ -241017,7 +242315,7 @@ static Fts5Colset *fts5ParseColset( assert( pParse->rc==SQLITE_OK ); assert( iCol>=0 && iColpConfig->nCol ); - pNew = sqlite3_realloc64(p, sizeof(Fts5Colset) + sizeof(int)*nCol); + pNew = sqlite3_realloc64(p, SZ_FTS5COLSET(nCol+1)); if( pNew==0 ){ pParse->rc = SQLITE_NOMEM; }else{ @@ -241052,7 +242350,7 @@ static Fts5Colset *sqlite3Fts5ParseColsetInvert(Fts5Parse *pParse, Fts5Colset *p int nCol = pParse->pConfig->nCol; pRet = (Fts5Colset*)sqlite3Fts5MallocZero(&pParse->rc, - sizeof(Fts5Colset) + sizeof(int)*nCol + SZ_FTS5COLSET(nCol+1) ); if( pRet ){ int i; @@ -241113,7 +242411,7 @@ static Fts5Colset *sqlite3Fts5ParseColset( static Fts5Colset *fts5CloneColset(int *pRc, Fts5Colset *pOrig){ Fts5Colset *pRet; if( pOrig ){ - sqlite3_int64 nByte = sizeof(Fts5Colset) + (pOrig->nCol-1) * sizeof(int); + sqlite3_int64 nByte = SZ_FTS5COLSET(pOrig->nCol); pRet = (Fts5Colset*)sqlite3Fts5MallocZero(pRc, nByte); if( pRet ){ memcpy(pRet, pOrig, (size_t)nByte); @@ -241281,7 +242579,7 @@ static Fts5ExprNode *fts5ParsePhraseToAnd( assert( pNear->nPhrase==1 ); assert( pParse->bPhraseToAnd ); - nByte = sizeof(Fts5ExprNode) + nTerm*sizeof(Fts5ExprNode*); + nByte = SZ_FTS5EXPRNODE(nTerm+1); pRet = (Fts5ExprNode*)sqlite3Fts5MallocZero(&pParse->rc, nByte); if( pRet ){ pRet->eType = FTS5_AND; @@ -241291,7 +242589,7 @@ static Fts5ExprNode *fts5ParsePhraseToAnd( pParse->nPhrase--; for(ii=0; iirc, sizeof(Fts5ExprPhrase) + &pParse->rc, SZ_FTS5EXPRPHRASE(1) ); if( pPhrase ){ if( parseGrowPhraseArray(pParse) ){ @@ -241360,7 +242658,7 @@ static Fts5ExprNode *sqlite3Fts5ParseNode( if( pRight->eType==eType ) nChild += pRight->nChild-1; } - nByte = sizeof(Fts5ExprNode) + sizeof(Fts5ExprNode*)*(nChild-1); + nByte = SZ_FTS5EXPRNODE(nChild); pRet = (Fts5ExprNode*)sqlite3Fts5MallocZero(&pParse->rc, nByte); if( pRet ){ @@ -242235,7 +243533,7 @@ static int sqlite3Fts5ExprInstToken( } /* -** Clear the token mappings for all Fts5IndexIter objects mannaged by +** Clear the token mappings for all Fts5IndexIter objects managed by ** the expression passed as the only argument. */ static void sqlite3Fts5ExprClearTokens(Fts5Expr *pExpr){ @@ -242270,7 +243568,7 @@ typedef struct Fts5HashEntry Fts5HashEntry; /* ** This file contains the implementation of an in-memory hash table used -** to accumuluate "term -> doclist" content before it is flused to a level-0 +** to accumulate "term -> doclist" content before it is flushed to a level-0 ** segment. */ @@ -242327,7 +243625,7 @@ struct Fts5HashEntry { }; /* -** Eqivalent to: +** Equivalent to: ** ** char *fts5EntryKey(Fts5HashEntry *pEntry){ return zKey; } */ @@ -243263,9 +244561,13 @@ struct Fts5Structure { u64 nOriginCntr; /* Origin value for next top-level segment */ int nSegment; /* Total segments in this structure */ int nLevel; /* Number of levels in this index */ - Fts5StructureLevel aLevel[1]; /* Array of nLevel level objects */ + Fts5StructureLevel aLevel[FLEXARRAY]; /* Array of nLevel level objects */ }; +/* Size (in bytes) of an Fts5Structure object holding up to N levels */ +#define SZ_FTS5STRUCTURE(N) \ + (offsetof(Fts5Structure,aLevel) + (N)*sizeof(Fts5StructureLevel)) + /* ** An object of type Fts5SegWriter is used to write to segments. */ @@ -243395,11 +244697,15 @@ struct Fts5SegIter { ** Array of tombstone pages. Reference counted. */ struct Fts5TombstoneArray { - int nRef; /* Number of pointers to this object */ + int nRef; /* Number of pointers to this object */ int nTombstone; - Fts5Data *apTombstone[1]; /* Array of tombstone pages */ + Fts5Data *apTombstone[FLEXARRAY]; /* Array of tombstone pages */ }; +/* Size (in bytes) of an Fts5TombstoneArray holding up to N tombstones */ +#define SZ_FTS5TOMBSTONEARRAY(N) \ + (offsetof(Fts5TombstoneArray,apTombstone)+(N)*sizeof(Fts5Data*)) + /* ** Argument is a pointer to an Fts5Data structure that contains a ** leaf page. @@ -243468,9 +244774,12 @@ struct Fts5Iter { i64 iSwitchRowid; /* Firstest rowid of other than aFirst[1] */ Fts5CResult *aFirst; /* Current merge state (see above) */ - Fts5SegIter aSeg[1]; /* Array of segment iterators */ + Fts5SegIter aSeg[FLEXARRAY]; /* Array of segment iterators */ }; +/* Size (in bytes) of an Fts5Iter object holding up to N segment iterators */ +#define SZ_FTS5ITER(N) (offsetof(Fts5Iter,aSeg)+(N)*sizeof(Fts5SegIter)) + /* ** An instance of the following type is used to iterate through the contents ** of a doclist-index record. @@ -243497,9 +244806,13 @@ struct Fts5DlidxLvl { struct Fts5DlidxIter { int nLvl; int iSegid; - Fts5DlidxLvl aLvl[1]; + Fts5DlidxLvl aLvl[FLEXARRAY]; }; +/* Size (in bytes) of an Fts5DlidxIter object with up to N levels */ +#define SZ_FTS5DLIDXITER(N) \ + (offsetof(Fts5DlidxIter,aLvl)+(N)*sizeof(Fts5DlidxLvl)) + static void fts5PutU16(u8 *aOut, u16 iVal){ aOut[0] = (iVal>>8); aOut[1] = (iVal&0xFF); @@ -243867,7 +245180,7 @@ static int sqlite3Fts5StructureTest(Fts5Index *p, void *pStruct){ static void fts5StructureMakeWritable(int *pRc, Fts5Structure **pp){ Fts5Structure *p = *pp; if( *pRc==SQLITE_OK && p->nRef>1 ){ - i64 nByte = sizeof(Fts5Structure)+(p->nLevel-1)*sizeof(Fts5StructureLevel); + i64 nByte = SZ_FTS5STRUCTURE(p->nLevel); Fts5Structure *pNew; pNew = (Fts5Structure*)sqlite3Fts5MallocZero(pRc, nByte); if( pNew ){ @@ -243941,10 +245254,7 @@ static int fts5StructureDecode( ){ return FTS5_CORRUPT; } - nByte = ( - sizeof(Fts5Structure) + /* Main structure */ - sizeof(Fts5StructureLevel) * (nLevel-1) /* aLevel[] array */ - ); + nByte = SZ_FTS5STRUCTURE(nLevel); pRet = (Fts5Structure*)sqlite3Fts5MallocZero(&rc, nByte); if( pRet ){ @@ -244024,10 +245334,7 @@ static void fts5StructureAddLevel(int *pRc, Fts5Structure **ppStruct){ if( *pRc==SQLITE_OK ){ Fts5Structure *pStruct = *ppStruct; int nLevel = pStruct->nLevel; - sqlite3_int64 nByte = ( - sizeof(Fts5Structure) + /* Main structure */ - sizeof(Fts5StructureLevel) * (nLevel+1) /* aLevel[] array */ - ); + sqlite3_int64 nByte = SZ_FTS5STRUCTURE(nLevel+2); pStruct = sqlite3_realloc64(pStruct, nByte); if( pStruct ){ @@ -244566,7 +245873,7 @@ static Fts5DlidxIter *fts5DlidxIterInit( int bDone = 0; for(i=0; p->rc==SQLITE_OK && bDone==0; i++){ - sqlite3_int64 nByte = sizeof(Fts5DlidxIter) + i * sizeof(Fts5DlidxLvl); + sqlite3_int64 nByte = SZ_FTS5DLIDXITER(i+1); Fts5DlidxIter *pNew; pNew = (Fts5DlidxIter*)sqlite3_realloc64(pIter, nByte); @@ -244784,7 +246091,7 @@ static void fts5SegIterSetNext(Fts5Index *p, Fts5SegIter *pIter){ static void fts5SegIterAllocTombstone(Fts5Index *p, Fts5SegIter *pIter){ const int nTomb = pIter->pSeg->nPgTombstone; if( nTomb>0 ){ - int nByte = nTomb * sizeof(Fts5Data*) + sizeof(Fts5TombstoneArray); + int nByte = SZ_FTS5TOMBSTONEARRAY(nTomb+1); Fts5TombstoneArray *pNew; pNew = (Fts5TombstoneArray*)sqlite3Fts5MallocZero(&p->rc, nByte); if( pNew ){ @@ -246245,8 +247552,7 @@ static Fts5Iter *fts5MultiIterAlloc( for(nSlot=2; nSlotaSeg[] */ + SZ_FTS5ITER(nSlot) + /* pNew + pNew->aSeg[] */ sizeof(Fts5CResult) * nSlot /* pNew->aFirst[] */ ); if( pNew ){ @@ -248047,7 +249353,7 @@ static void fts5DoSecureDelete( int iDelKeyOff = 0; /* Offset of deleted key, if any */ nIdx = nPg-iPgIdx; - aIdx = sqlite3Fts5MallocZero(&p->rc, nIdx+16); + aIdx = sqlite3Fts5MallocZero(&p->rc, ((i64)nIdx)+16); if( p->rc ) return; memcpy(aIdx, &aPg[iPgIdx], nIdx); @@ -248612,7 +249918,7 @@ static Fts5Structure *fts5IndexOptimizeStruct( Fts5Structure *pStruct ){ Fts5Structure *pNew = 0; - sqlite3_int64 nByte = sizeof(Fts5Structure); + sqlite3_int64 nByte = SZ_FTS5STRUCTURE(1); int nSeg = pStruct->nSegment; int i; @@ -248641,7 +249947,8 @@ static Fts5Structure *fts5IndexOptimizeStruct( assert( pStruct->aLevel[i].nMerge<=nThis ); } - nByte += (pStruct->nLevel+1) * sizeof(Fts5StructureLevel); + nByte += (((i64)pStruct->nLevel)+1) * sizeof(Fts5StructureLevel); + assert( nByte==SZ_FTS5STRUCTURE(pStruct->nLevel+2) ); pNew = (Fts5Structure*)sqlite3Fts5MallocZero(&p->rc, nByte); if( pNew ){ @@ -249218,9 +250525,13 @@ struct Fts5TokenDataIter { int nIterAlloc; Fts5PoslistReader *aPoslistReader; int *aPoslistToIter; - Fts5Iter *apIter[1]; + Fts5Iter *apIter[FLEXARRAY]; }; +/* Size in bytes of an Fts5TokenDataIter object holding up to N iterators */ +#define SZ_FTS5TOKENDATAITER(N) \ + (offsetof(Fts5TokenDataIter,apIter) + (N)*sizeof(Fts5Iter)) + /* ** The two input arrays - a1[] and a2[] - are in sorted order. This function ** merges the two arrays together and writes the result to output array @@ -249292,7 +250603,7 @@ static void fts5TokendataIterAppendMap( /* ** Sort the contents of the pT->aMap[] array. ** -** The sorting algorithm requries a malloc(). If this fails, an error code +** The sorting algorithm requires a malloc(). If this fails, an error code ** is left in Fts5Index.rc before returning. */ static void fts5TokendataIterSortMap(Fts5Index *p, Fts5TokenDataIter *pT){ @@ -249483,7 +250794,7 @@ static void fts5SetupPrefixIter( && p->pConfig->bPrefixInsttoken ){ s.pTokendata = &s2; - s2.pT = (Fts5TokenDataIter*)fts5IdxMalloc(p, sizeof(*s2.pT)); + s2.pT = (Fts5TokenDataIter*)fts5IdxMalloc(p, SZ_FTS5TOKENDATAITER(1)); } if( p->pConfig->eDetail==FTS5_DETAIL_NONE ){ @@ -249529,7 +250840,8 @@ static void fts5SetupPrefixIter( } } - pData = fts5IdxMalloc(p, sizeof(*pData)+s.doclist.n+FTS5_DATA_ZERO_PADDING); + pData = fts5IdxMalloc(p, sizeof(*pData) + + ((i64)s.doclist.n)+FTS5_DATA_ZERO_PADDING); assert( pData!=0 || p->rc!=SQLITE_OK ); if( pData ){ pData->p = (u8*)&pData[1]; @@ -249610,15 +250922,17 @@ static int sqlite3Fts5IndexRollback(Fts5Index *p){ ** and the initial version of the "averages" record (a zero-byte blob). */ static int sqlite3Fts5IndexReinit(Fts5Index *p){ - Fts5Structure s; + Fts5Structure *pTmp; + u8 tmpSpace[SZ_FTS5STRUCTURE(1)]; fts5StructureInvalidate(p); fts5IndexDiscardData(p); - memset(&s, 0, sizeof(Fts5Structure)); + pTmp = (Fts5Structure*)tmpSpace; + memset(pTmp, 0, SZ_FTS5STRUCTURE(1)); if( p->pConfig->bContentlessDelete ){ - s.nOriginCntr = 1; + pTmp->nOriginCntr = 1; } fts5DataWrite(p, FTS5_AVERAGES_ROWID, (const u8*)"", 0); - fts5StructureWrite(p, &s); + fts5StructureWrite(p, pTmp); return fts5IndexReturn(p); } @@ -249826,7 +251140,7 @@ static Fts5TokenDataIter *fts5AppendTokendataIter( if( p->rc==SQLITE_OK ){ if( pIn==0 || pIn->nIter==pIn->nIterAlloc ){ int nAlloc = pIn ? pIn->nIterAlloc*2 : 16; - int nByte = nAlloc * sizeof(Fts5Iter*) + sizeof(Fts5TokenDataIter); + int nByte = SZ_FTS5TOKENDATAITER(nAlloc+1); Fts5TokenDataIter *pNew = (Fts5TokenDataIter*)sqlite3_realloc(pIn, nByte); if( pNew==0 ){ @@ -250342,7 +251656,8 @@ static int fts5SetupPrefixIterTokendata( fts5BufferGrow(&p->rc, &token, nToken+1); assert( token.p!=0 || p->rc!=SQLITE_OK ); - ctx.pT = (Fts5TokenDataIter*)sqlite3Fts5MallocZero(&p->rc, sizeof(*ctx.pT)); + ctx.pT = (Fts5TokenDataIter*)sqlite3Fts5MallocZero(&p->rc, + SZ_FTS5TOKENDATAITER(1)); if( p->rc==SQLITE_OK ){ @@ -250473,7 +251788,8 @@ static int sqlite3Fts5IndexIterWriteTokendata( if( pIter->nSeg>0 ){ /* This is a prefix term iterator. */ if( pT==0 ){ - pT = (Fts5TokenDataIter*)sqlite3Fts5MallocZero(&p->rc, sizeof(*pT)); + pT = (Fts5TokenDataIter*)sqlite3Fts5MallocZero(&p->rc, + SZ_FTS5TOKENDATAITER(1)); pIter->pTokenDataIter = pT; } if( pT ){ @@ -251507,7 +252823,7 @@ static void fts5DecodeRowid( #if defined(SQLITE_TEST) || defined(SQLITE_FTS5_DEBUG) static void fts5DebugRowid(int *pRc, Fts5Buffer *pBuf, i64 iKey){ - int iSegid, iHeight, iPgno, bDlidx, bTomb; /* Rowid compenents */ + int iSegid, iHeight, iPgno, bDlidx, bTomb; /* Rowid components */ fts5DecodeRowid(iKey, &bTomb, &iSegid, &bDlidx, &iHeight, &iPgno); if( iSegid==0 ){ @@ -251753,7 +253069,7 @@ static void fts5DecodeFunction( ** buffer overreads even if the record is corrupt. */ n = sqlite3_value_bytes(apVal[1]); aBlob = sqlite3_value_blob(apVal[1]); - nSpace = n + FTS5_DATA_ZERO_PADDING; + nSpace = ((i64)n) + FTS5_DATA_ZERO_PADDING; a = (u8*)sqlite3Fts5MallocZero(&rc, nSpace); if( a==0 ) goto decode_out; if( n>0 ) memcpy(a, aBlob, n); @@ -252468,9 +253784,11 @@ struct Fts5Sorter { i64 iRowid; /* Current rowid */ const u8 *aPoslist; /* Position lists for current row */ int nIdx; /* Number of entries in aIdx[] */ - int aIdx[1]; /* Offsets into aPoslist for current row */ + int aIdx[FLEXARRAY]; /* Offsets into aPoslist for current row */ }; +/* Size (int bytes) of an Fts5Sorter object with N indexes */ +#define SZ_FTS5SORTER(N) (offsetof(Fts5Sorter,nIdx)+((N+2)/2)*sizeof(i64)) /* ** Virtual-table cursor object. @@ -253348,7 +254666,7 @@ static int fts5CursorFirstSorted( const char *zRankArgs = pCsr->zRankArgs; nPhrase = sqlite3Fts5ExprPhraseCount(pCsr->pExpr); - nByte = sizeof(Fts5Sorter) + sizeof(int) * (nPhrase-1); + nByte = SZ_FTS5SORTER(nPhrase); pSorter = (Fts5Sorter*)sqlite3_malloc64(nByte); if( pSorter==0 ) return SQLITE_NOMEM; memset(pSorter, 0, (size_t)nByte); @@ -255874,7 +257192,7 @@ static void fts5SourceIdFunc( ){ assert( nArg==0 ); UNUSED_PARAM2(nArg, apUnused); - sqlite3_result_text(pCtx, "fts5: 2025-02-18 13:38:58 873d4e274b4988d260ba8354a9718324a1c26187a4ab4c1cc0227c03d0f10e70", -1, SQLITE_TRANSIENT); + sqlite3_result_text(pCtx, "fts5: 2025-05-29 14:26:00 dfc790f998f450d9c35e3ba1c8c89c17466cb559f87b0239e4aab9d34e28f742", -1, SQLITE_TRANSIENT); } /* @@ -256099,8 +257417,8 @@ static int fts5Init(sqlite3 *db){ ** its entry point to enable the matchinfo() demo. */ #ifdef SQLITE_FTS5_ENABLE_TEST_MI if( rc==SQLITE_OK ){ - extern int sqlite3Fts5TestRegisterMatchinfo(sqlite3*); - rc = sqlite3Fts5TestRegisterMatchinfo(db); + extern int sqlite3Fts5TestRegisterMatchinfoAPI(fts5_api*); + rc = sqlite3Fts5TestRegisterMatchinfoAPI(&pGlobal->api); } #endif @@ -259938,7 +261256,6 @@ static void sqlite3Fts5UnicodeAscii(u8 *aArray, u8 *aAscii){ aAscii[0] = 0; /* 0x00 is never a token character */ } - /* ** 2015 May 30 ** @@ -260479,12 +261796,12 @@ static int fts5VocabInitVtab( *pzErr = sqlite3_mprintf("wrong number of vtable arguments"); rc = SQLITE_ERROR; }else{ - int nByte; /* Bytes of space to allocate */ + i64 nByte; /* Bytes of space to allocate */ const char *zDb = bDb ? argv[3] : argv[1]; const char *zTab = bDb ? argv[4] : argv[3]; const char *zType = bDb ? argv[5] : argv[4]; - int nDb = (int)strlen(zDb)+1; - int nTab = (int)strlen(zTab)+1; + i64 nDb = strlen(zDb)+1; + i64 nTab = strlen(zTab)+1; int eType = 0; rc = fts5VocabTableType(zType, pzErr, &eType); diff --git a/deps/sqlite/sqlite3.h b/deps/sqlite/sqlite3.h index 082a9f9dc44e93..f61a1485754531 100644 --- a/deps/sqlite/sqlite3.h +++ b/deps/sqlite/sqlite3.h @@ -133,7 +133,7 @@ extern "C" { ** ** Since [version 3.6.18] ([dateof:3.6.18]), ** SQLite source code has been stored in the -** Fossil configuration management +** Fossil configuration management ** system. ^The SQLITE_SOURCE_ID macro evaluates to ** a string which identifies a particular check-in of SQLite ** within its configuration management system. ^The SQLITE_SOURCE_ID @@ -146,9 +146,9 @@ extern "C" { ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ -#define SQLITE_VERSION "3.49.1" -#define SQLITE_VERSION_NUMBER 3049001 -#define SQLITE_SOURCE_ID "2025-02-18 13:38:58 873d4e274b4988d260ba8354a9718324a1c26187a4ab4c1cc0227c03d0f10e70" +#define SQLITE_VERSION "3.50.0" +#define SQLITE_VERSION_NUMBER 3050000 +#define SQLITE_SOURCE_ID "2025-05-29 14:26:00 dfc790f998f450d9c35e3ba1c8c89c17466cb559f87b0239e4aab9d34e28f742" /* ** CAPI3REF: Run-Time Library Version Numbers @@ -1163,6 +1163,12 @@ struct sqlite3_io_methods { ** the value that M is to be set to. Before returning, the 32-bit signed ** integer is overwritten with the previous value of M. ** +**
  • [[SQLITE_FCNTL_BLOCK_ON_CONNECT]] +** The [SQLITE_FCNTL_BLOCK_ON_CONNECT] opcode is used to configure the +** VFS to block when taking a SHARED lock to connect to a wal mode database. +** This is used to implement the functionality associated with +** SQLITE_SETLK_BLOCK_ON_CONNECT. +** **
  • [[SQLITE_FCNTL_DATA_VERSION]] ** The [SQLITE_FCNTL_DATA_VERSION] opcode is used to detect changes to ** a database file. The argument is a pointer to a 32-bit unsigned integer. @@ -1259,6 +1265,7 @@ struct sqlite3_io_methods { #define SQLITE_FCNTL_CKSM_FILE 41 #define SQLITE_FCNTL_RESET_CACHE 42 #define SQLITE_FCNTL_NULL_IO 43 +#define SQLITE_FCNTL_BLOCK_ON_CONNECT 44 /* deprecated names */ #define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE @@ -1989,13 +1996,16 @@ struct sqlite3_mem_methods { ** ** [[SQLITE_CONFIG_LOOKASIDE]]
    SQLITE_CONFIG_LOOKASIDE
    **
    ^(The SQLITE_CONFIG_LOOKASIDE option takes two arguments that determine -** the default size of lookaside memory on each [database connection]. +** the default size of [lookaside memory] on each [database connection]. ** The first argument is the -** size of each lookaside buffer slot and the second is the number of -** slots allocated to each database connection.)^ ^(SQLITE_CONFIG_LOOKASIDE -** sets the default lookaside size. The [SQLITE_DBCONFIG_LOOKASIDE] -** option to [sqlite3_db_config()] can be used to change the lookaside -** configuration on individual connections.)^
    +** size of each lookaside buffer slot ("sz") and the second is the number of +** slots allocated to each database connection ("cnt").)^ +** ^(SQLITE_CONFIG_LOOKASIDE sets the default lookaside size. +** The [SQLITE_DBCONFIG_LOOKASIDE] option to [sqlite3_db_config()] can +** be used to change the lookaside configuration on individual connections.)^ +** The [-DSQLITE_DEFAULT_LOOKASIDE] option can be used to change the +** default lookaside configuration at compile-time. +**
  • ** ** [[SQLITE_CONFIG_PCACHE2]]
    SQLITE_CONFIG_PCACHE2
    **
    ^(The SQLITE_CONFIG_PCACHE2 option takes a single argument which is @@ -2232,31 +2242,50 @@ struct sqlite3_mem_methods { ** [[SQLITE_DBCONFIG_LOOKASIDE]] **
    SQLITE_DBCONFIG_LOOKASIDE
    **
    The SQLITE_DBCONFIG_LOOKASIDE option is used to adjust the -** configuration of the lookaside memory allocator within a database +** configuration of the [lookaside memory allocator] within a database ** connection. ** The arguments to the SQLITE_DBCONFIG_LOOKASIDE option are not ** in the [DBCONFIG arguments|usual format]. ** The SQLITE_DBCONFIG_LOOKASIDE option takes three arguments, not two, ** so that a call to [sqlite3_db_config()] that uses SQLITE_DBCONFIG_LOOKASIDE ** should have a total of five parameters. -** ^The first argument (the third parameter to [sqlite3_db_config()] is a +**
      +**
    1. The first argument ("buf") is a ** pointer to a memory buffer to use for lookaside memory. -** ^The first argument after the SQLITE_DBCONFIG_LOOKASIDE verb -** may be NULL in which case SQLite will allocate the -** lookaside buffer itself using [sqlite3_malloc()]. ^The second argument is the -** size of each lookaside buffer slot. ^The third argument is the number of -** slots. The size of the buffer in the first argument must be greater than -** or equal to the product of the second and third arguments. The buffer -** must be aligned to an 8-byte boundary. ^If the second argument to -** SQLITE_DBCONFIG_LOOKASIDE is not a multiple of 8, it is internally -** rounded down to the next smaller multiple of 8. ^(The lookaside memory +** The first argument may be NULL in which case SQLite will allocate the +** lookaside buffer itself using [sqlite3_malloc()]. +**

    2. The second argument ("sz") is the +** size of each lookaside buffer slot. Lookaside is disabled if "sz" +** is less than 8. The "sz" argument should be a multiple of 8 less than +** 65536. If "sz" does not meet this constraint, it is reduced in size until +** it does. +**

    3. The third argument ("cnt") is the number of slots. Lookaside is disabled +** if "cnt"is less than 1. The "cnt" value will be reduced, if necessary, so +** that the product of "sz" and "cnt" does not exceed 2,147,418,112. The "cnt" +** parameter is usually chosen so that the product of "sz" and "cnt" is less +** than 1,000,000. +**

    +**

    If the "buf" argument is not NULL, then it must +** point to a memory buffer with a size that is greater than +** or equal to the product of "sz" and "cnt". +** The buffer must be aligned to an 8-byte boundary. +** The lookaside memory ** configuration for a database connection can only be changed when that ** connection is not currently using lookaside memory, or in other words -** when the "current value" returned by -** [sqlite3_db_status](D,[SQLITE_DBSTATUS_LOOKASIDE_USED],...) is zero. +** when the value returned by [SQLITE_DBSTATUS_LOOKASIDE_USED] is zero. ** Any attempt to change the lookaside memory configuration when lookaside ** memory is in use leaves the configuration unchanged and returns -** [SQLITE_BUSY].)^

    +** [SQLITE_BUSY]. +** If the "buf" argument is NULL and an attempt +** to allocate memory based on "sz" and "cnt" fails, then +** lookaside is silently disabled. +**

    +** The [SQLITE_CONFIG_LOOKASIDE] configuration option can be used to set the +** default lookaside configuration at initialization. The +** [-DSQLITE_DEFAULT_LOOKASIDE] option can be used to set the default lookaside +** configuration at compile-time. Typical values for lookaside are 1200 for +** "sz" and 40 to 100 for "cnt". +** ** ** [[SQLITE_DBCONFIG_ENABLE_FKEY]] **

    SQLITE_DBCONFIG_ENABLE_FKEY
    @@ -2993,6 +3022,44 @@ SQLITE_API int sqlite3_busy_handler(sqlite3*,int(*)(void*,int),void*); */ SQLITE_API int sqlite3_busy_timeout(sqlite3*, int ms); +/* +** CAPI3REF: Set the Setlk Timeout +** METHOD: sqlite3 +** +** This routine is only useful in SQLITE_ENABLE_SETLK_TIMEOUT builds. If +** the VFS supports blocking locks, it sets the timeout in ms used by +** eligible locks taken on wal mode databases by the specified database +** handle. In non-SQLITE_ENABLE_SETLK_TIMEOUT builds, or if the VFS does +** not support blocking locks, this function is a no-op. +** +** Passing 0 to this function disables blocking locks altogether. Passing +** -1 to this function requests that the VFS blocks for a long time - +** indefinitely if possible. The results of passing any other negative value +** are undefined. +** +** Internally, each SQLite database handle store two timeout values - the +** busy-timeout (used for rollback mode databases, or if the VFS does not +** support blocking locks) and the setlk-timeout (used for blocking locks +** on wal-mode databases). The sqlite3_busy_timeout() method sets both +** values, this function sets only the setlk-timeout value. Therefore, +** to configure separate busy-timeout and setlk-timeout values for a single +** database handle, call sqlite3_busy_timeout() followed by this function. +** +** Whenever the number of connections to a wal mode database falls from +** 1 to 0, the last connection takes an exclusive lock on the database, +** then checkpoints and deletes the wal file. While it is doing this, any +** new connection that tries to read from the database fails with an +** SQLITE_BUSY error. Or, if the SQLITE_SETLK_BLOCK_ON_CONNECT flag is +** passed to this API, the new connection blocks until the exclusive lock +** has been released. +*/ +SQLITE_API int sqlite3_setlk_timeout(sqlite3*, int ms, int flags); + +/* +** CAPI3REF: Flags for sqlite3_setlk_timeout() +*/ +#define SQLITE_SETLK_BLOCK_ON_CONNECT 0x01 + /* ** CAPI3REF: Convenience Routines For Running Queries ** METHOD: sqlite3 @@ -5108,7 +5175,7 @@ SQLITE_API const void *sqlite3_column_decltype16(sqlite3_stmt*,int); ** other than [SQLITE_ROW] before any subsequent invocation of ** sqlite3_step(). Failure to reset the prepared statement using ** [sqlite3_reset()] would result in an [SQLITE_MISUSE] return from -** sqlite3_step(). But after [version 3.6.23.1] ([dateof:3.6.23.1], +** sqlite3_step(). But after [version 3.6.23.1] ([dateof:3.6.23.1]), ** sqlite3_step() began ** calling [sqlite3_reset()] automatically in this circumstance rather ** than returning [SQLITE_MISUSE]. This is not considered a compatibility @@ -7004,6 +7071,8 @@ SQLITE_API int sqlite3_autovacuum_pages( ** ** ^The second argument is a pointer to the function to invoke when a ** row is updated, inserted or deleted in a rowid table. +** ^The update hook is disabled by invoking sqlite3_update_hook() +** with a NULL pointer as the second parameter. ** ^The first argument to the callback is a copy of the third argument ** to sqlite3_update_hook(). ** ^The second callback argument is one of [SQLITE_INSERT], [SQLITE_DELETE], @@ -11486,9 +11555,10 @@ SQLITE_API void sqlite3session_table_filter( ** is inserted while a session object is enabled, then later deleted while ** the same session object is disabled, no INSERT record will appear in the ** changeset, even though the delete took place while the session was disabled. -** Or, if one field of a row is updated while a session is disabled, and -** another field of the same row is updated while the session is enabled, the -** resulting changeset will contain an UPDATE change that updates both fields. +** Or, if one field of a row is updated while a session is enabled, and +** then another field of the same row is updated while the session is disabled, +** the resulting changeset will contain an UPDATE change that updates both +** fields. */ SQLITE_API int sqlite3session_changeset( sqlite3_session *pSession, /* Session object */ @@ -11560,8 +11630,9 @@ SQLITE_API sqlite3_int64 sqlite3session_changeset_size(sqlite3_session *pSession ** database zFrom the contents of the two compatible tables would be ** identical. ** -** It an error if database zFrom does not exist or does not contain the -** required compatible table. +** Unless the call to this function is a no-op as described above, it is an +** error if database zFrom does not exist or does not contain the required +** compatible table. ** ** If the operation is successful, SQLITE_OK is returned. Otherwise, an SQLite ** error code. In this case, if argument pzErrMsg is not NULL, *pzErrMsg @@ -11696,7 +11767,7 @@ SQLITE_API int sqlite3changeset_start_v2( ** The following flags may passed via the 4th parameter to ** [sqlite3changeset_start_v2] and [sqlite3changeset_start_v2_strm]: ** -**
    SQLITE_CHANGESETAPPLY_INVERT
    +**
    SQLITE_CHANGESETSTART_INVERT
    ** Invert the changeset while iterating through it. This is equivalent to ** inverting a changeset using sqlite3changeset_invert() before applying it. ** It is an error to specify this flag with a patchset. @@ -12011,19 +12082,6 @@ SQLITE_API int sqlite3changeset_concat( void **ppOut /* OUT: Buffer containing output changeset */ ); - -/* -** CAPI3REF: Upgrade the Schema of a Changeset/Patchset -*/ -SQLITE_API int sqlite3changeset_upgrade( - sqlite3 *db, - const char *zDb, - int nIn, const void *pIn, /* Input changeset */ - int *pnOut, void **ppOut /* OUT: Inverse of input */ -); - - - /* ** CAPI3REF: Changegroup Handle ** diff --git a/deps/sqlite/sqlite3ext.h b/deps/sqlite/sqlite3ext.h index ae0949baf75ae8..cf775dfbde0fdf 100644 --- a/deps/sqlite/sqlite3ext.h +++ b/deps/sqlite/sqlite3ext.h @@ -366,6 +366,8 @@ struct sqlite3_api_routines { /* Version 3.44.0 and later */ void *(*get_clientdata)(sqlite3*,const char*); int (*set_clientdata)(sqlite3*, const char*, void*, void(*)(void*)); + /* Version 3.50.0 and later */ + int (*setlk_timeout)(sqlite3*,int,int); }; /* @@ -699,6 +701,8 @@ typedef int (*sqlite3_loadext_entry)( /* Version 3.44.0 and later */ #define sqlite3_get_clientdata sqlite3_api->get_clientdata #define sqlite3_set_clientdata sqlite3_api->set_clientdata +/* Version 3.50.0 and later */ +#define sqlite3_setlk_timeout sqlite3_api->setlk_timeout #endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */ #if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) diff --git a/deps/uv/.mailmap b/deps/uv/.mailmap index 97f5d1f2c004c9..f5d5375e044e18 100644 --- a/deps/uv/.mailmap +++ b/deps/uv/.mailmap @@ -52,6 +52,7 @@ San-Tai Hsu Santiago Gimeno Saúl Ibarra Corretgé Saúl Ibarra Corretgé +Saúl Ibarra Corretgé Shigeki Ohtsu Shuowang (Wayne) Zhang TK-one diff --git a/deps/uv/.readthedocs.yaml b/deps/uv/.readthedocs.yaml index b16bf0d4ab754b..5290ec33e89899 100644 --- a/deps/uv/.readthedocs.yaml +++ b/deps/uv/.readthedocs.yaml @@ -2,7 +2,7 @@ version: 2 sphinx: builder: html - configuration: null + configuration: docs/src/conf.py fail_on_warning: false build: diff --git a/deps/uv/AUTHORS b/deps/uv/AUTHORS index 041b7aff610f57..89a3d9db05c877 100644 --- a/deps/uv/AUTHORS +++ b/deps/uv/AUTHORS @@ -588,5 +588,19 @@ Raihaan Shouhell Rialbat Adam Poul T Lomholt -dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Thad House +Julian A Avar C <28635807+julian-a-avar-c@users.noreply.github.com> +amcgoogan <105525867+amcgoogan@users.noreply.github.com> +Rafael Gonzaga +Morten Engelhardt Olsen +Andrey +Julio Jordán +Jinho Jang +Velikiy Kirill +rainlow <37818892+rainlow@users.noreply.github.com> +Paolo Insogna +Robert Nagy +mugitya03 +Itay Bookstein +crupest +AE1020 <68134252+AE1020@users.noreply.github.com> diff --git a/deps/uv/CMakeLists.txt b/deps/uv/CMakeLists.txt index 28c6df25666967..73d5aff8926ed5 100644 --- a/deps/uv/CMakeLists.txt +++ b/deps/uv/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.9) +cmake_minimum_required(VERSION 3.10) if(POLICY CMP0091) cmake_policy(SET CMP0091 NEW) # Enable MSVC_RUNTIME_LIBRARY setting @@ -20,7 +20,7 @@ include(CTest) set(CMAKE_C_VISIBILITY_PRESET hidden) set(CMAKE_C_STANDARD_REQUIRED ON) set(CMAKE_C_EXTENSIONS ON) -set(CMAKE_C_STANDARD 90) +set(CMAKE_C_STANDARD 11) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) @@ -186,7 +186,7 @@ set(uv_sources src/version.c) if(WIN32) - list(APPEND uv_defines WIN32_LEAN_AND_MEAN _WIN32_WINNT=0x0602 _CRT_DECLARE_NONSTDC_NAMES=0) + list(APPEND uv_defines WIN32_LEAN_AND_MEAN _WIN32_WINNT=0x0A00 _CRT_DECLARE_NONSTDC_NAMES=0) list(APPEND uv_libraries psapi user32 @@ -434,6 +434,7 @@ endif() if(APPLE OR CMAKE_SYSTEM_NAME MATCHES "DragonFly|FreeBSD|Linux|NetBSD|OpenBSD") list(APPEND uv_test_libraries util) + list(APPEND uv_libraries m) endif() if(CYGWIN OR MSYS) @@ -583,6 +584,7 @@ if(LIBUV_BUILD_TESTS) test/test-loop-close.c test/test-loop-configure.c test/test-loop-handles.c + test/test-loop-oom.c test/test-loop-stop.c test/test-loop-time.c test/test-metrics.c @@ -667,6 +669,7 @@ if(LIBUV_BUILD_TESTS) test/test-thread-affinity.c test/test-thread-equal.c test/test-thread.c + test/test-thread-name.c test/test-thread-priority.c test/test-threadpool-cancel.c test/test-threadpool.c diff --git a/deps/uv/ChangeLog b/deps/uv/ChangeLog index dc2dd2790c57d3..787963715772d0 100644 --- a/deps/uv/ChangeLog +++ b/deps/uv/ChangeLog @@ -1,4 +1,175 @@ -2024.10.18, Version 1.49.2 (Stable) +2025.04.25, Version 1.51.0 (Stable) + +Changes since version 1.50.0: + +* win: fix leak in uv_os_tmpdir (Saúl Ibarra Corretgé) + +* docs: fix RTD build (Saúl Ibarra Corretgé) + +* win: lazy-load [GS]etThreadDescription symbols (Ben Noordhuis) + +* linux: try preadv64/pwritev64 before preadv/pwritev (Ben Noordhuis) + +* win: check cwd length before spawning a child process (Morten Engelhardt + Olsen) + +* macos,bsd: handle missing /dev/null in chroot env (Andrey) + +* doc: fix README link text (Julio Jordán) + +* win: fix order of FILE_STAT_BASIC_INFORMATION struct fields (Hüseyin Açacak) + +* macos: increase child process stdio buffer size (Jinho Jang) + +* doc: add C3 bindings to LINKS.md (Velikiy Kirill) + +* unix: remove unnecessary errno.h include in poll.c (Juan José Arboleda) + +* win: fix the inconsistency in volume serial number (Hüseyin Açacak) + +* unix: add thread affinity support on openharmony (rainlow) + +* unix: enable getrusage for SunOS (Paolo Insogna) + +* unix,win: accept NAN/INFINITY as file timestamps (Ben Noordhuis) + +* win: add ENABLE_VIRTUAL_TERMINAL_INPUT raw tty mode (Anna Henningsen) + +* test: handle UV_ENOTSUP in platform_output (cjihrig) + +* doc: fix rendering of threading.html (Tobias Nießen) + +* unix,sunos: enable use of sendmmsg on Solaris and Illumos (Stacey Marshall) + +* unix: handle out of memory in iface name copy (Ben Noordhuis) + +* openbsd: do not error out if cpuspeed is not available (Robert Nagy) + +* test: skip thread_name_threadpool on AIX/IBMi (Abdirahim Musse) + +* aix,ibmi: fix undeclared identifiers (Richard Lau) + +* unix,sunos: prefer SO_REUSEPORT for load balancing (Stacey Marshall) + +* doc: free lib pointer before function return (mugitya03) + +* test: link with libm (Juan José Arboleda) + +* style: rename parameter to match definition (Mohammed Keyvanzadeh) + +* test: support partial output lines in test runner (cjihrig) + +* build: switch from c90 to c11 (Ben Noordhuis) + +* linux: allow nul bytes in abstract socket address (Itay Bookstein) + +* sunos: use pipe2 on solaris and illumos (Andy Pan) + +* unix: remove TOCTOU issues from uv_pipe_chmod (Ben Noordhuis) + +* unix: use pipe_fname if getsockname returns nothing (crupest) + +* haiku: use uint32 instead of uint32_t (AE1020) + +* doc: update thread pool stack size comment (Ben Noordhuis) + +* unix: improve uv_loop_init OOM handling (Ben Noordhuis) + +* test: merge uv_tcp_connect callbacks (Juan José Arboleda) + +* test: skip multievent tests on macOS with TSAN enabled (Juan José Arboleda) + +* linux: align CPU quota calculation with Rust (Juan José Arboleda) + +* kqueue: improve fs event watcher OOM handling (Juan José Arboleda) + +* sunos: improve fs event watcher OOM handling (Juan José Arboleda) + +* build: shorten instructions for cmake build (Juan José Arboleda) + + +2025.01.15, Version 1.50.0 (Stable), 8fb9cb919489a48880680a56efecff6a7dfb4504 + +Changes since version 1.49.2: + +* ci: run macOS and iOS tests also on macOS 14 (Saúl Ibarra Corretgé) + +* unix,win: map ENOEXEC errno (Saúl Ibarra Corretgé) + +* test: skip multicast join test on ENOEXEC (Saúl Ibarra Corretgé) + +* ci: make sure the macOS firewall is disabled (Saúl Ibarra Corretgé) + +* darwin,test: squelch EBUSY error on multicast join (Saúl Ibarra Corretgé) + +* build: update minimum cmake to 3.10 (Ben Noordhuis) + +* kqueue: use EVFILT_USER for async if available (Jameson Nash) + +* unix,win: fix off-by-one in uv_wtf8_to_utf16() (Ben Noordhuis) + +* doc: add scala-native-loop to LINKS.md (Julian A Avar C) + +* unix: fix build breakage on haiku, openbsd, etc (Jeffrey H. Johnson) + +* kqueue: lower overhead in uv__io_check_fd (Andy Pan) + +* doc: move cjihrig back to active maintainers (cjihrig) + +* build(deps): bump actions/checkout from 3 to 4 (dependabot[bot]) + +* unix,pipe: fix handling null buffer in uv_pipe_get{sock,peer}name (Saúl + Ibarra Corretgé) + +* unix,win: harmonize buffer checking (Saúl Ibarra Corretgé) + +* unix,win: add support for detached threads (Juan José Arboleda) + +* src: add uv_thread_set/getname() methods (Santiago Gimeno) + +* build: fix qemu builds (Ben Noordhuis) + +* win: drop support for windows 8 (Ben Noordhuis) + +* linux: fix uv_cpu_info() arm cpu model detection (Ben Noordhuis) + +* linux: always use io_uring for epoll batching (Ben Noordhuis) + +* doc: clarify repeating timer behavior more (Ben Noordhuis) + +* unix,win: handle nbufs=0 in uv_udp_try_send (Ben Noordhuis) + +* win: use GetQueuedCompletionStatusEx directly (Saúl Ibarra Corretgé) + +* win: enable uv_thread_{get,set}name on MinGW (Saúl Ibarra Corretgé) + +* win: drop support for the legacy MinGW (Saúl Ibarra Corretgé) + +* win,fs: get (most) fstat when no permission (Jameson Nash) + +* win: plug uv_fs_event_start memory leak (amcgoogan) + +* test: address FreeBSD kernel bug causing NULL path in fsevents (Juan José + Arboleda) + +* unix: refactor udp sendmsg code (Ben Noordhuis) + +* unix,win: add uv_udp_try_send2 (Ben Noordhuis) + +* test: fix flaky flaky udp_mmsg test (Juan José Arboleda) + +* build: enable fdsan in Android (Juan José Arboleda) + +* test: fix udp-multicast-join for FreeBSD (Juan José Arboleda) + +* win: fix leak processing fs event (Saúl Ibarra Corretgé) + +* src: set a default thread name for workers (Rafael Gonzaga) + +* misc: implement uv_getrusage_thread (Juan José Arboleda) + + +2024.10.18, Version 1.49.2 (Stable), e1095c7a4373ce00cd8874d8e820de5afb25776e Changes since version 1.49.1: diff --git a/deps/uv/LINKS.md b/deps/uv/LINKS.md index 3e5800747bc7dd..9f286ea3e9201f 100644 --- a/deps/uv/LINKS.md +++ b/deps/uv/LINKS.md @@ -37,6 +37,7 @@ * [Pixie-io](https://github.com/pixie-io/pixie): Open-source observability tool for Kubernetes applications. * [potion](https://github.com/perl11/potion)/[p2](https://github.com/perl11/p2): runtime * [racer](https://libraries.io/rubygems/racer): Ruby web server written as an C extension +* [scala-native-loop](https://github.com/scala-native/scala-native-loop): Extensible event loop and async-oriented IO for Scala Native; powered by libuv * [Socket Runtime](https://sockets.sh): A runtime for creating native cross-platform software on mobile and desktop using HTML, CSS, and JavaScript * [spider-gazelle](https://github.com/cotag/spider-gazelle): Ruby web server using libuv bindings * [Suave](http://suave.io/): A simple web development F# library providing a lightweight web server and a set of combinators to manipulate route flow and task composition @@ -107,3 +108,5 @@ * [node.pas](https://github.com/vovach777/node.pas) NodeJS-like ecosystem * Haskell * [Z.Haskell](https://z.haskell.world) +* C3 + * [libuv.c3l](https://github.com/velikoss/libuv.c3l) diff --git a/deps/uv/MAINTAINERS.md b/deps/uv/MAINTAINERS.md index 41c60cb383cfbe..ff8be88b7b7cd5 100644 --- a/deps/uv/MAINTAINERS.md +++ b/deps/uv/MAINTAINERS.md @@ -4,6 +4,9 @@ libuv is currently managed by the following individuals: * **Ben Noordhuis** ([@bnoordhuis](https://github.com/bnoordhuis)) - GPG key: D77B 1E34 243F BAF0 5F8E 9CC3 4F55 C8C8 46AB 89B9 (pubkey-bnoordhuis) +* **Colin Ihrig** ([@cjihrig](https://github.com/cjihrig)) + - GPG key: 94AE 3667 5C46 4D64 BAFA 68DD 7434 390B DBE9 B9C5 (pubkey-cjihrig) + - GPG key: 5735 3E0D BDAA A7E8 39B6 6A1A FF47 D5E4 AD8B 4FDC (pubkey-cjihrig-kb) * **Jameson Nash** ([@vtjnash](https://github.com/vtjnash)) - GPG key: AEAD 0A4B 6867 6775 1A0E 4AEF 34A2 5FB1 2824 6514 (pubkey-vtjnash) - GPG key: CFBB 9CA9 A5BE AFD7 0E2B 3C5A 79A6 7C55 A367 9C8B (pubkey2022-vtjnash) @@ -24,9 +27,6 @@ libuv is currently managed by the following individuals: * **Anna Henningsen** ([@addaleax](https://github.com/addaleax)) * **Bartosz Sosnowski** ([@bzoz](https://github.com/bzoz)) * **Bert Belder** ([@piscisaureus](https://github.com/piscisaureus)) -* **Colin Ihrig** ([@cjihrig](https://github.com/cjihrig)) - - GPG key: 94AE 3667 5C46 4D64 BAFA 68DD 7434 390B DBE9 B9C5 (pubkey-cjihrig) - - GPG key: 5735 3E0D BDAA A7E8 39B6 6A1A FF47 D5E4 AD8B 4FDC (pubkey-cjihrig-kb) * **Fedor Indutny** ([@indutny](https://github.com/indutny)) - GPG key: AF2E EA41 EC34 47BF DD86 FED9 D706 3CCE 19B7 E890 (pubkey-indutny) * **Imran Iqbal** ([@imran-iq](https://github.com/imran-iq)) diff --git a/deps/uv/Makefile.am b/deps/uv/Makefile.am index f85a41316c8a43..f3808b696ce3db 100644 --- a/deps/uv/Makefile.am +++ b/deps/uv/Makefile.am @@ -59,7 +59,7 @@ if WINNT uvinclude_HEADERS += include/uv/win.h include/uv/tree.h AM_CPPFLAGS += -I$(top_srcdir)/src/win \ -DWIN32_LEAN_AND_MEAN \ - -D_WIN32_WINNT=0x0602 + -D_WIN32_WINNT=0x0A00 libuv_la_SOURCES += src/win/async.c \ src/win/atomicops-inl.h \ src/win/core.c \ @@ -206,12 +206,13 @@ test_run_tests_SOURCES = test/blackhole-server.c \ test/test-ipc-send-recv.c \ test/test-ipc.c \ test/test-list.h \ - test/test-loop-handles.c \ test/test-loop-alive.c \ test/test-loop-close.c \ + test/test-loop-configure.c \ + test/test-loop-handles.c \ + test/test-loop-oom.c \ test/test-loop-stop.c \ test/test-loop-time.c \ - test/test-loop-configure.c \ test/test-metrics.c \ test/test-multiple-listen.c \ test/test-mutexes.c \ @@ -294,6 +295,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \ test/test-thread-equal.c \ test/test-thread.c \ test/test-thread-affinity.c \ + test/test-thread-name.c \ test/test-thread-priority.c \ test/test-threadpool-cancel.c \ test/test-threadpool.c \ diff --git a/deps/uv/README.md b/deps/uv/README.md index 12c3061a894c56..7cc9d2dd53c27c 100644 --- a/deps/uv/README.md +++ b/deps/uv/README.md @@ -189,9 +189,7 @@ $ make install To build with [CMake][]: ```bash -$ mkdir -p build - -$ (cd build && cmake .. -DBUILD_TESTING=ON) # generate project with tests +$ cmake -B build -DBUILD_TESTING=ON # generate project with tests $ cmake --build build # add `-j ` with cmake >= 3.12 # Run tests: diff --git a/deps/uv/SUPPORTED_PLATFORMS.md b/deps/uv/SUPPORTED_PLATFORMS.md index 8a435d2592e47f..c560aa1086b981 100644 --- a/deps/uv/SUPPORTED_PLATFORMS.md +++ b/deps/uv/SUPPORTED_PLATFORMS.md @@ -4,14 +4,14 @@ |---|---|---|---| | GNU/Linux | Tier 1 | Linux >= 3.10 with glibc >= 2.17 | | | macOS | Tier 1 | macOS >= 11 | Currently supported macOS releases | -| Windows | Tier 1 | >= Windows 8 | VS 2015 and later are supported | +| Windows | Tier 1 | >= Windows 10 | VS 2017 and later are supported | | FreeBSD | Tier 2 | >= 12 | | | AIX | Tier 2 | >= 6 | Maintainers: @libuv/aix | | IBM i | Tier 2 | >= IBM i 7.2 | Maintainers: @libuv/ibmi | | z/OS | Tier 2 | >= V2R2 | Maintainers: @libuv/zos | | Linux with musl | Tier 2 | musl >= 1.0 | | | Android | Tier 3 | NDK >= r15b | Android 7.0, `-DANDROID_PLATFORM=android-24` | -| MinGW | Tier 3 | MinGW32 and MinGW-w64 | | +| MinGW | Tier 3 | MinGW-w64 | | | SunOS | Tier 3 | Solaris 121 and later | | | Other | Tier 3 | N/A | | diff --git a/deps/uv/configure.ac b/deps/uv/configure.ac index 98c59363026f86..a4b03b8f5075ee 100644 --- a/deps/uv/configure.ac +++ b/deps/uv/configure.ac @@ -13,7 +13,7 @@ # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. AC_PREREQ(2.57) -AC_INIT([libuv], [1.49.2], [https://github.com/libuv/libuv/issues]) +AC_INIT([libuv], [1.51.0], [https://github.com/libuv/libuv/issues]) AC_CONFIG_MACRO_DIR([m4]) m4_include([m4/libuv-extra-automake-flags.m4]) m4_include([m4/as_case.m4]) @@ -33,7 +33,7 @@ CC_ATTRIBUTE_VISIBILITY([default], [ # we exclude -fno-strict-aliasing for xlc CC_CHECK_FLAG_SUPPORTED_APPEND([-fno-strict-aliasing]) CC_CHECK_CFLAGS_APPEND([-g]) -CC_CHECK_CFLAGS_APPEND([-std=gnu89]) +CC_CHECK_CFLAGS_APPEND([-std=gnu11]) CC_CHECK_CFLAGS_APPEND([-Wall]) CC_CHECK_CFLAGS_APPEND([-Wextra]) CC_CHECK_CFLAGS_APPEND([-Wno-long-long]) diff --git a/deps/uv/docs/src/fs.rst b/deps/uv/docs/src/fs.rst index 7bc8d0cbfd165d..01a48e8edd85d8 100644 --- a/deps/uv/docs/src/fs.rst +++ b/deps/uv/docs/src/fs.rst @@ -430,6 +430,12 @@ API Equivalent to :man:`utime(2)`, :man:`futimes(3)` and :man:`lutimes(3)` respectively. + Passing `UV_FS_UTIME_NOW` as the atime or mtime sets the timestamp to the + current time. + + Passing `UV_FS_UTIME_OMIT` as the atime or mtime leaves the timestamp + untouched. + .. note:: z/OS: `uv_fs_lutime()` is not implemented for z/OS. It can still be called but will return ``UV_ENOSYS``. diff --git a/deps/uv/docs/src/fs_event.rst b/deps/uv/docs/src/fs_event.rst index 983db1a9d5608a..bfdecdd7329cd2 100644 --- a/deps/uv/docs/src/fs_event.rst +++ b/deps/uv/docs/src/fs_event.rst @@ -47,6 +47,11 @@ Data types The `events` parameter is an ORed mask of :c:enum:`uv_fs_event` elements. +.. note:: + For FreeBSD path could sometimes be `NULL` due to a kernel bug. + + .. _Reference: https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=197695 + .. c:enum:: uv_fs_event Event types that :c:type:`uv_fs_event_t` handles monitor. diff --git a/deps/uv/docs/src/index.rst b/deps/uv/docs/src/index.rst index 5bdb4be84b6ea1..448de4066d66f7 100644 --- a/deps/uv/docs/src/index.rst +++ b/deps/uv/docs/src/index.rst @@ -58,5 +58,5 @@ libuv can be downloaded from `here `_. Installation ------------ -Installation instructions can be found in `the README `_. +Installation instructions can be found in the `README `_. diff --git a/deps/uv/docs/src/misc.rst b/deps/uv/docs/src/misc.rst index 61883b7e21e527..db95e2dde83ea1 100644 --- a/deps/uv/docs/src/misc.rst +++ b/deps/uv/docs/src/misc.rst @@ -360,6 +360,17 @@ API On Windows not all fields are set, the unsupported fields are filled with zeroes. See :c:type:`uv_rusage_t` for more details. +.. c:function:: int uv_getrusage_thread(uv_rusage_t* rusage) + + Gets the resource usage measures for the calling thread. + + .. versionadded:: 1.50.0 + + .. note:: + Not supported on all platforms. May return `UV_ENOTSUP`. + On macOS and Windows not all fields are set, the unsupported fields are filled with zeroes. + See :c:type:`uv_rusage_t` for more details. + .. c:function:: uv_pid_t uv_os_getpid(void) Returns the current process ID. diff --git a/deps/uv/docs/src/threading.rst b/deps/uv/docs/src/threading.rst index 883218fa829ccb..27c1d6ee28a44d 100644 --- a/deps/uv/docs/src/threading.rst +++ b/deps/uv/docs/src/threading.rst @@ -78,6 +78,14 @@ Threads .. versionchanged:: 1.4.1 returns a UV_E* error code on failure +.. c:function:: int uv_thread_detach(uv_thread_t* tid) + + Detaches a thread. Detached threads automatically release their + resources upon termination, eliminating the need for the application to + call `uv_thread_join`. + + .. versionadded:: 1.50.0 + .. c:function:: int uv_thread_create_ex(uv_thread_t* tid, const uv_thread_options_t* params, uv_thread_cb entry, void* arg) Like :c:func:`uv_thread_create`, but additionally specifies options for creating a new thread. @@ -132,7 +140,29 @@ Threads .. c:function:: int uv_thread_join(uv_thread_t *tid) .. c:function:: int uv_thread_equal(const uv_thread_t* t1, const uv_thread_t* t2) +.. c:function:: int uv_thread_setname(const char* name) + + Sets the name of the current thread. Different platforms define different limits on the max number of characters + a thread name can be: Linux, IBM i (16), macOS (64), Windows (32767), and NetBSD (32), etc. `uv_thread_setname()` + will truncate it in case `name` is larger than the limit of the platform. + + Not supported on Windows Server 2016, returns `UV_ENOSYS`. + + .. versionadded:: 1.50.0 + +.. c:function:: int uv_thread_getname(uv_thread_t* tid, char* name, size_t* size) + + Gets the name of the thread specified by `tid`. The thread name is copied, with the trailing NUL, into the buffer + pointed to by `name`. The `size` parameter specifies the size of the buffer pointed to by `name`. + The buffer should be large enough to hold the name of the thread plus the trailing NUL, or it will be truncated to fit + with the trailing NUL. + + Not supported on Windows Server 2016, returns `UV_ENOSYS`. + + .. versionadded:: 1.50.0 + .. c:function:: int uv_thread_setpriority(uv_thread_t tid, int priority) + If the function succeeds, the return value is 0. If the function fails, the return value is less than zero. Sets the scheduling priority of the thread specified by tid. It requires elevated @@ -140,7 +170,9 @@ Threads The priority can be set to the following constants. UV_THREAD_PRIORITY_HIGHEST, UV_THREAD_PRIORITY_ABOVE_NORMAL, UV_THREAD_PRIORITY_NORMAL, UV_THREAD_PRIORITY_BELOW_NORMAL, UV_THREAD_PRIORITY_LOWEST. + .. c:function:: int uv_thread_getpriority(uv_thread_t tid, int* priority) + If the function succeeds, the return value is 0. If the function fails, the return value is less than zero. Retrieves the scheduling priority of the thread specified by tid. The value in the diff --git a/deps/uv/docs/src/threadpool.rst b/deps/uv/docs/src/threadpool.rst index 7cfa797314ca48..d4dc5b8ec56097 100644 --- a/deps/uv/docs/src/threadpool.rst +++ b/deps/uv/docs/src/threadpool.rst @@ -17,11 +17,13 @@ is 1024). .. versionchanged:: 1.45.0 threads now have an 8 MB stack instead of the (sometimes too low) platform default. +.. versionchanged:: 1.50.0 threads now have a default name of libuv-worker. + The threadpool is global and shared across all event loops. When a particular -function makes use of the threadpool (i.e. when using :c:func:`uv_queue_work`) +function makes use of the threadpool (e.g. when using :c:func:`uv_queue_work`) libuv preallocates and initializes the maximum number of threads allowed by -``UV_THREADPOOL_SIZE``. This causes a relatively minor memory overhead -(~1MB for 128 threads) but increases the performance of threading at runtime. +``UV_THREADPOOL_SIZE``. More threads usually means more throughput but a higher +memory footprint. Thread stacks grow lazily on most platforms though. .. note:: Note that even though a global thread pool which is shared across all events diff --git a/deps/uv/docs/src/timer.rst b/deps/uv/docs/src/timer.rst index 070fa79da9d6df..474c6b8c4cd4f6 100644 --- a/deps/uv/docs/src/timer.rst +++ b/deps/uv/docs/src/timer.rst @@ -6,6 +6,15 @@ Timer handles are used to schedule callbacks to be called in the future. +Timers are either single-shot or repeating. Repeating timers do not adjust +for overhead but are rearmed relative to the event loop's idea of "now". + +Libuv updates its idea of "now" right before executing timer callbacks, and +right after waking up from waiting for I/O. See also :c:func:`uv_update_time`. + +Example: a repeating timer with a 50 ms interval whose callback takes 17 ms +to complete, runs again 33 ms later. If other tasks take longer than 33 ms, +the timer callback runs as soon as possible. Data types ---------- @@ -64,11 +73,6 @@ API duration, and will follow normal timer semantics in the case of a time-slice overrun. - For example, if a 50ms repeating timer first runs for 17ms, it will be - scheduled to run again 33ms later. If other tasks consume more than the - 33ms following the first timer callback, then the callback will run as soon - as possible. - .. note:: If the repeat value is set from a timer callback it does not immediately take effect. If the timer was non-repeating before, it will have been stopped. If it was repeating, diff --git a/deps/uv/docs/src/tty.rst b/deps/uv/docs/src/tty.rst index 7a2235210bf62a..b461b24437c187 100644 --- a/deps/uv/docs/src/tty.rst +++ b/deps/uv/docs/src/tty.rst @@ -27,10 +27,15 @@ Data types typedef enum { /* Initial/normal terminal mode */ UV_TTY_MODE_NORMAL, - /* Raw input mode (On Windows, ENABLE_WINDOW_INPUT is also enabled) */ + /* + * Raw input mode (On Windows, ENABLE_WINDOW_INPUT is also enabled). + * May become equivalent to UV_TTY_MODE_RAW_VT in future libuv versions. + */ UV_TTY_MODE_RAW, /* Binary-safe I/O mode for IPC (Unix-only) */ - UV_TTY_MODE_IO + UV_TTY_MODE_IO, + /* Raw input mode. On Windows ENABLE_VIRTUAL_TERMINAL_INPUT is also set. */ + UV_TTY_MODE_RAW_VT } uv_tty_mode_t; .. c:enum:: uv_tty_vtermstate_t diff --git a/deps/uv/docs/src/udp.rst b/deps/uv/docs/src/udp.rst index 31f7f7fd71ff47..5f225e5cda4011 100644 --- a/deps/uv/docs/src/udp.rst +++ b/deps/uv/docs/src/udp.rst @@ -426,6 +426,20 @@ API .. versionchanged:: 1.27.0 added support for connected sockets +.. c:function:: int uv_udp_try_send2(uv_udp_t* handle, unsigned int count, uv_buf_t* bufs[/*count*/], unsigned int nbufs[/*count*/], struct sockaddr* addrs[/*count*/], unsigned int flags) + + Like :c:func:`uv_udp_try_send`, but can send multiple datagrams. + Lightweight abstraction around :man:`sendmmsg(2)`, with a :man:`sendmsg(2)` + fallback loop for platforms that do not support the former. The handle must + be fully initialized; call c:func:`uv_udp_bind` first. + + :returns: >= 0: number of datagrams sent. Zero only if `count` was zero. + < 0: negative error code. Only if sending the first datagram fails, + otherwise returns a positive send count. ``UV_EAGAIN`` when datagrams + cannot be sent right now; fall back to :c:func:`uv_udp_send`. + + .. versionadded:: 1.50.0 + .. c:function:: int uv_udp_recv_start(uv_udp_t* handle, uv_alloc_cb alloc_cb, uv_udp_recv_cb recv_cb) Prepare for receiving data. If the socket has not previously been bound diff --git a/deps/uv/include/uv.h b/deps/uv/include/uv.h index 9e450c5110fe57..938e998fdc54d1 100644 --- a/deps/uv/include/uv.h +++ b/deps/uv/include/uv.h @@ -58,6 +58,7 @@ extern "C" { #include #include #include +#include /* Internal type, do not use. */ struct uv__queue { @@ -157,6 +158,7 @@ struct uv__queue { XX(ESOCKTNOSUPPORT, "socket type not supported") \ XX(ENODATA, "no data available") \ XX(EUNATCH, "protocol driver not attached") \ + XX(ENOEXEC, "exec format error") \ #define UV_HANDLE_TYPE_MAP(XX) \ XX(ASYNC, async) \ @@ -775,6 +777,12 @@ UV_EXTERN int uv_udp_try_send(uv_udp_t* handle, const uv_buf_t bufs[], unsigned int nbufs, const struct sockaddr* addr); +UV_EXTERN int uv_udp_try_send2(uv_udp_t* handle, + unsigned int count, + uv_buf_t* bufs[/*count*/], + unsigned int nbufs[/*count*/], + struct sockaddr* addrs[/*count*/], + unsigned int flags); UV_EXTERN int uv_udp_recv_start(uv_udp_t* handle, uv_alloc_cb alloc_cb, uv_udp_recv_cb recv_cb); @@ -798,10 +806,15 @@ struct uv_tty_s { typedef enum { /* Initial/normal terminal mode */ UV_TTY_MODE_NORMAL, - /* Raw input mode (On Windows, ENABLE_WINDOW_INPUT is also enabled) */ + /* + * Raw input mode (On Windows, ENABLE_WINDOW_INPUT is also enabled). + * May become equivalent to UV_TTY_MODE_RAW_VT in future libuv versions. + */ UV_TTY_MODE_RAW, /* Binary-safe I/O mode for IPC (Unix-only) */ - UV_TTY_MODE_IO + UV_TTY_MODE_IO, + /* Raw input mode. On Windows ENABLE_VIRTUAL_TERMINAL_INPUT is also set. */ + UV_TTY_MODE_RAW_VT } uv_tty_mode_t; typedef enum { @@ -1288,6 +1301,7 @@ typedef struct { } uv_rusage_t; UV_EXTERN int uv_getrusage(uv_rusage_t* rusage); +UV_EXTERN int uv_getrusage_thread(uv_rusage_t* rusage); UV_EXTERN int uv_os_homedir(char* buffer, size_t* size); UV_EXTERN int uv_os_tmpdir(char* buffer, size_t* size); @@ -1577,6 +1591,8 @@ UV_EXTERN int uv_fs_chmod(uv_loop_t* loop, const char* path, int mode, uv_fs_cb cb); +#define UV_FS_UTIME_NOW (INFINITY) +#define UV_FS_UTIME_OMIT (NAN) UV_EXTERN int uv_fs_utime(uv_loop_t* loop, uv_fs_t* req, const char* path, @@ -1869,6 +1885,7 @@ UV_EXTERN int uv_gettimeofday(uv_timeval64_t* tv); typedef void (*uv_thread_cb)(void* arg); UV_EXTERN int uv_thread_create(uv_thread_t* tid, uv_thread_cb entry, void* arg); +UV_EXTERN int uv_thread_detach(uv_thread_t* tid); typedef enum { UV_THREAD_NO_FLAGS = 0x00, @@ -1898,6 +1915,9 @@ UV_EXTERN int uv_thread_getcpu(void); UV_EXTERN uv_thread_t uv_thread_self(void); UV_EXTERN int uv_thread_join(uv_thread_t *tid); UV_EXTERN int uv_thread_equal(const uv_thread_t* t1, const uv_thread_t* t2); +UV_EXTERN int uv_thread_setname(const char* name); +UV_EXTERN int uv_thread_getname(uv_thread_t* tid, char* name, size_t size); + /* The presence of these unions force similar struct layout. */ #define XX(_, name) uv_ ## name ## _t name; diff --git a/deps/uv/include/uv/errno.h b/deps/uv/include/uv/errno.h index 127278ef916161..ac00778cfc59fb 100644 --- a/deps/uv/include/uv/errno.h +++ b/deps/uv/include/uv/errno.h @@ -474,4 +474,10 @@ # define UV__EUNATCH (-4023) #endif +#if defined(ENOEXEC) && !defined(_WIN32) +# define UV__ENOEXEC UV__ERR(ENOEXEC) +#else +# define UV__ENOEXEC (-4022) +#endif + #endif /* UV_ERRNO_H_ */ diff --git a/deps/uv/include/uv/unix.h b/deps/uv/include/uv/unix.h index 538f98b6c5d657..7c972026f688e8 100644 --- a/deps/uv/include/uv/unix.h +++ b/deps/uv/include/uv/unix.h @@ -271,7 +271,10 @@ typedef struct { #define UV_UDP_SEND_PRIVATE_FIELDS \ struct uv__queue queue; \ - struct sockaddr_storage addr; \ + union { \ + struct sockaddr addr; \ + struct sockaddr_storage storage; \ + } u; \ unsigned int nbufs; \ uv_buf_t* bufs; \ ssize_t status; \ diff --git a/deps/uv/include/uv/version.h b/deps/uv/include/uv/version.h index cfa7871322e690..77432f259588eb 100644 --- a/deps/uv/include/uv/version.h +++ b/deps/uv/include/uv/version.h @@ -31,8 +31,8 @@ */ #define UV_VERSION_MAJOR 1 -#define UV_VERSION_MINOR 49 -#define UV_VERSION_PATCH 2 +#define UV_VERSION_MINOR 51 +#define UV_VERSION_PATCH 0 #define UV_VERSION_IS_RELEASE 1 #define UV_VERSION_SUFFIX "" diff --git a/deps/uv/include/uv/win.h b/deps/uv/include/uv/win.h index 12ac53b4f217d2..a88bf29e9ff504 100644 --- a/deps/uv/include/uv/win.h +++ b/deps/uv/include/uv/win.h @@ -20,7 +20,7 @@ */ #ifndef _WIN32_WINNT -# define _WIN32_WINNT 0x0600 +# define _WIN32_WINNT 0x0A00 #endif #if !defined(_SSIZE_T_) && !defined(_SSIZE_T_DEFINED) @@ -32,14 +32,6 @@ typedef intptr_t ssize_t; #include -#if defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR) -typedef struct pollfd { - SOCKET fd; - short events; - short revents; -} WSAPOLLFD, *PWSAPOLLFD, *LPWSAPOLLFD; -#endif - #ifndef LOCALE_INVARIANT # define LOCALE_INVARIANT 0x007f #endif @@ -507,8 +499,11 @@ typedef struct { union { \ struct { \ /* Used for readable TTY handles */ \ - /* TODO: remove me in v2.x. */ \ - HANDLE unused_; \ + union { \ + /* TODO: remove me in v2.x. */ \ + HANDLE unused_; \ + int mode; \ + } mode; \ uv_buf_t read_line_buffer; \ HANDLE read_raw_wait; \ /* Fields used for translating win keystrokes into vt100 characters */ \ diff --git a/deps/uv/src/fs-poll.c b/deps/uv/src/fs-poll.c index 1bac1c568e36ca..1fadafdea1746a 100644 --- a/deps/uv/src/fs-poll.c +++ b/deps/uv/src/fs-poll.c @@ -51,7 +51,7 @@ struct poll_ctx { static int statbuf_eq(const uv_stat_t* a, const uv_stat_t* b); static void poll_cb(uv_fs_t* req); static void timer_cb(uv_timer_t* timer); -static void timer_close_cb(uv_handle_t* handle); +static void timer_close_cb(uv_handle_t* timer); static uv_stat_t zero_statbuf; @@ -139,6 +139,9 @@ int uv_fs_poll_getpath(uv_fs_poll_t* handle, char* buffer, size_t* size) { struct poll_ctx* ctx; size_t required_len; + if (buffer == NULL || size == NULL || *size == 0) + return UV_EINVAL; + if (!uv_is_active((uv_handle_t*)handle)) { *size = 0; return UV_EINVAL; diff --git a/deps/uv/src/idna.c b/deps/uv/src/idna.c index efc5f283ce2ef9..5fcaf64c974a8a 100644 --- a/deps/uv/src/idna.c +++ b/deps/uv/src/idna.c @@ -393,7 +393,7 @@ void uv_wtf8_to_utf16(const char* source_ptr, code_point = uv__wtf8_decode1(&source_ptr); /* uv_wtf8_length_as_utf16 should have been called and checked first. */ assert(code_point >= 0); - if (code_point > 0x10000) { + if (code_point > 0xFFFF) { assert(code_point < 0x10FFFF); *w_target++ = (((code_point - 0x10000) >> 10) + 0xD800); *w_target++ = ((code_point - 0x10000) & 0x3FF) + 0xDC00; diff --git a/deps/uv/src/threadpool.c b/deps/uv/src/threadpool.c index 45af50dcd04ea6..98d81cc7b6a4ed 100644 --- a/deps/uv/src/threadpool.c +++ b/deps/uv/src/threadpool.c @@ -59,6 +59,7 @@ static void worker(void* arg) { struct uv__queue* q; int is_slow_work; + uv_thread_setname("libuv-worker"); uv_sem_post((uv_sem_t*) arg); arg = NULL; diff --git a/deps/uv/src/unix/aix.c b/deps/uv/src/unix/aix.c index 3af3009a2167d6..48da0c9c40c842 100644 --- a/deps/uv/src/unix/aix.c +++ b/deps/uv/src/unix/aix.c @@ -1120,6 +1120,8 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { struct ifreq *ifr, *p, flg; struct in6_ifreq if6; struct sockaddr_dl* sa_addr; + size_t namelen; + char* name; ifc.ifc_req = NULL; sock6fd = -1; @@ -1156,6 +1158,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { #define ADDR_SIZE(p) MAX((p).sa_len, sizeof(p)) /* Count all up and running ipv4/ipv6 addresses */ + namelen = 0; ifr = ifc.ifc_req; while ((char*)ifr < (char*)ifc.ifc_req + ifc.ifc_len) { p = ifr; @@ -1175,6 +1178,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { if (!(flg.ifr_flags & IFF_UP && flg.ifr_flags & IFF_RUNNING)) continue; + namelen += strlen(p->ifr_name) + 1; (*count)++; } @@ -1182,11 +1186,12 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { goto cleanup; /* Alloc the return interface structs */ - *addresses = uv__calloc(*count, sizeof(**addresses)); - if (!(*addresses)) { + *addresses = uv__calloc(1, *count * sizeof(**addresses) + namelen); + if (*addresses == NULL) { r = UV_ENOMEM; goto cleanup; } + name = (char*) &(*addresses)[*count]; address = *addresses; ifr = ifc.ifc_req; @@ -1210,7 +1215,9 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { /* All conditions above must match count loop */ - address->name = uv__strdup(p->ifr_name); + namelen = strlen(p->ifr_name) + 1; + address->name = memcpy(name, p->ifr_name, namelen); + name += namelen; if (inet6) address->address.address6 = *((struct sockaddr_in6*) &p->ifr_addr); @@ -1282,13 +1289,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { void uv_free_interface_addresses(uv_interface_address_t* addresses, - int count) { - int i; - - for (i = 0; i < count; ++i) { - uv__free(addresses[i].name); - } - + int count) { uv__free(addresses); } diff --git a/deps/uv/src/unix/async.c b/deps/uv/src/unix/async.c index 0ff2669e30a628..538ae7876f2b24 100644 --- a/deps/uv/src/unix/async.c +++ b/deps/uv/src/unix/async.c @@ -38,6 +38,34 @@ #include #endif +#if UV__KQUEUE_EVFILT_USER +static uv_once_t kqueue_runtime_detection_guard = UV_ONCE_INIT; +static int kqueue_evfilt_user_support = 1; + + +static void uv__kqueue_runtime_detection(void) { + int kq; + struct kevent ev[2]; + struct timespec timeout = {0, 0}; + + /* Perform the runtime detection to ensure that kqueue with + * EVFILT_USER actually works. */ + kq = kqueue(); + EV_SET(ev, UV__KQUEUE_EVFILT_USER_IDENT, EVFILT_USER, + EV_ADD | EV_CLEAR, 0, 0, 0); + EV_SET(ev + 1, UV__KQUEUE_EVFILT_USER_IDENT, EVFILT_USER, + 0, NOTE_TRIGGER, 0, 0); + if (kevent(kq, ev, 2, ev, 1, &timeout) < 1 || + ev[0].filter != EVFILT_USER || + ev[0].ident != UV__KQUEUE_EVFILT_USER_IDENT || + ev[0].flags & EV_ERROR) + /* If we wind up here, we can assume that EVFILT_USER is defined but + * broken on the current system. */ + kqueue_evfilt_user_support = 0; + uv__close(kq); +} +#endif + static void uv__async_send(uv_loop_t* loop); static int uv__async_start(uv_loop_t* loop); static void uv__cpu_relax(void); @@ -139,7 +167,11 @@ static void uv__async_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { assert(w == &loop->async_io_watcher); +#if UV__KQUEUE_EVFILT_USER + for (;!kqueue_evfilt_user_support;) { +#else for (;;) { +#endif r = read(w->fd, buf, sizeof(buf)); if (r == sizeof(buf)) @@ -195,6 +227,17 @@ static void uv__async_send(uv_loop_t* loop) { len = sizeof(val); fd = loop->async_io_watcher.fd; /* eventfd */ } +#elif UV__KQUEUE_EVFILT_USER + struct kevent ev; + + if (kqueue_evfilt_user_support) { + fd = loop->async_io_watcher.fd; /* magic number for EVFILT_USER */ + EV_SET(&ev, fd, EVFILT_USER, 0, NOTE_TRIGGER, 0, 0); + r = kevent(loop->backend_fd, &ev, 1, NULL, 0, NULL); + if (r == 0) + return; + abort(); + } #endif do @@ -215,6 +258,9 @@ static void uv__async_send(uv_loop_t* loop) { static int uv__async_start(uv_loop_t* loop) { int pipefd[2]; int err; +#if UV__KQUEUE_EVFILT_USER + struct kevent ev; +#endif if (loop->async_io_watcher.fd != -1) return 0; @@ -226,16 +272,59 @@ static int uv__async_start(uv_loop_t* loop) { pipefd[0] = err; pipefd[1] = -1; +#elif UV__KQUEUE_EVFILT_USER + uv_once(&kqueue_runtime_detection_guard, uv__kqueue_runtime_detection); + if (kqueue_evfilt_user_support) { + /* In order not to break the generic pattern of I/O polling, a valid + * file descriptor is required to take up a room in loop->watchers, + * thus we create one for that, but this fd will not be actually used, + * it's just a placeholder and magic number which is going to be closed + * during the cleanup, as other FDs. */ + err = uv__open_cloexec("/", O_RDONLY); + if (err < 0) + return err; + + pipefd[0] = err; + pipefd[1] = -1; + + /* When using EVFILT_USER event to wake up the kqueue, this event must be + * registered beforehand. Otherwise, calling kevent() to issue an + * unregistered EVFILT_USER event will get an ENOENT. + * Since uv__async_send() may happen before uv__io_poll() with multi-threads, + * we can't defer this registration of EVFILT_USER event as we did for other + * events, but must perform it right away. */ + EV_SET(&ev, err, EVFILT_USER, EV_ADD | EV_CLEAR, 0, 0, 0); + err = kevent(loop->backend_fd, &ev, 1, NULL, 0, NULL); + if (err < 0) + return UV__ERR(errno); + } else { + err = uv__make_pipe(pipefd, UV_NONBLOCK_PIPE); + if (err < 0) + return err; + } #else err = uv__make_pipe(pipefd, UV_NONBLOCK_PIPE); if (err < 0) return err; #endif - uv__io_init(&loop->async_io_watcher, uv__async_io, pipefd[0]); - uv__io_start(loop, &loop->async_io_watcher, POLLIN); + err = uv__io_init_start(loop, &loop->async_io_watcher, uv__async_io, + pipefd[0], POLLIN); + if (err < 0) { + uv__close(pipefd[0]); + if (pipefd[1] != -1) + uv__close(pipefd[1]); + return err; + } loop->async_wfd = pipefd[1]; +#if UV__KQUEUE_EVFILT_USER + /* Prevent the EVFILT_USER event from being added to kqueue redundantly + * and mistakenly later in uv__io_poll(). */ + if (kqueue_evfilt_user_support) + loop->async_io_watcher.events = loop->async_io_watcher.pevents; +#endif + return 0; } diff --git a/deps/uv/src/unix/bsd-ifaddrs.c b/deps/uv/src/unix/bsd-ifaddrs.c index 11ca95591fc382..8d9ebd25d4306b 100644 --- a/deps/uv/src/unix/bsd-ifaddrs.c +++ b/deps/uv/src/unix/bsd-ifaddrs.c @@ -65,13 +65,13 @@ static int uv__ifaddr_exclude(struct ifaddrs *ent, int exclude_type) { return 0; } +/* TODO(bnoordhuis) share with linux.c */ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { + uv_interface_address_t* address; struct ifaddrs* addrs; struct ifaddrs* ent; - uv_interface_address_t* address; -#if !(defined(__CYGWIN__) || defined(__MSYS__)) && !defined(__GNU__) - int i; -#endif + size_t namelen; + char* name; *count = 0; *addresses = NULL; @@ -80,9 +80,11 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { return UV__ERR(errno); /* Count the number of interfaces */ + namelen = 0; for (ent = addrs; ent != NULL; ent = ent->ifa_next) { if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFADDR)) continue; + namelen += strlen(ent->ifa_name) + 1; (*count)++; } @@ -92,20 +94,22 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { } /* Make sure the memory is initiallized to zero using calloc() */ - *addresses = uv__calloc(*count, sizeof(**addresses)); - + *addresses = uv__calloc(1, *count * sizeof(**addresses) + namelen); if (*addresses == NULL) { freeifaddrs(addrs); return UV_ENOMEM; } + name = (char*) &(*addresses)[*count]; address = *addresses; for (ent = addrs; ent != NULL; ent = ent->ifa_next) { if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFADDR)) continue; - address->name = uv__strdup(ent->ifa_name); + namelen = strlen(ent->ifa_name) + 1; + address->name = memcpy(name, ent->ifa_name, namelen); + name += namelen; if (ent->ifa_addr->sa_family == AF_INET6) { address->address.address6 = *((struct sockaddr_in6*) ent->ifa_addr); @@ -129,6 +133,8 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { #if !(defined(__CYGWIN__) || defined(__MSYS__)) && !defined(__GNU__) /* Fill in physical addresses for each interface */ for (ent = addrs; ent != NULL; ent = ent->ifa_next) { + int i; + if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFPHYS)) continue; @@ -151,13 +157,8 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { } +/* TODO(bnoordhuis) share with linux.c */ void uv_free_interface_addresses(uv_interface_address_t* addresses, int count) { - int i; - - for (i = 0; i < count; i++) { - uv__free(addresses[i].name); - } - uv__free(addresses); } diff --git a/deps/uv/src/unix/core.c b/deps/uv/src/unix/core.c index 0c52ccf2ad7b2d..bd51b69b8120e8 100644 --- a/deps/uv/src/unix/core.c +++ b/deps/uv/src/unix/core.c @@ -52,6 +52,8 @@ #endif #if defined(__APPLE__) +# include +# include # include # include #endif /* defined(__APPLE__) */ @@ -751,7 +753,7 @@ ssize_t uv__recvmsg(int fd, struct msghdr* msg, int flags) { int uv_cwd(char* buffer, size_t* size) { char scratch[1 + UV__PATH_MAX]; - if (buffer == NULL || size == NULL) + if (buffer == NULL || size == NULL || *size == 0) return UV_EINVAL; /* Try to read directly into the user's buffer first... */ @@ -865,7 +867,7 @@ static unsigned int next_power_of_two(unsigned int val) { return val; } -static void maybe_resize(uv_loop_t* loop, unsigned int len) { +static int maybe_resize(uv_loop_t* loop, unsigned int len) { uv__io_t** watchers; void* fake_watcher_list; void* fake_watcher_count; @@ -873,7 +875,7 @@ static void maybe_resize(uv_loop_t* loop, unsigned int len) { unsigned int i; if (len <= loop->nwatchers) - return; + return 0; /* Preserve fake watcher list and count at the end of the watchers */ if (loop->watchers != NULL) { @@ -889,7 +891,7 @@ static void maybe_resize(uv_loop_t* loop, unsigned int len) { (nwatchers + 2) * sizeof(loop->watchers[0])); if (watchers == NULL) - abort(); + return UV_ENOMEM; for (i = loop->nwatchers; i < nwatchers; i++) watchers[i] = NULL; watchers[nwatchers] = fake_watcher_list; @@ -897,11 +899,11 @@ static void maybe_resize(uv_loop_t* loop, unsigned int len) { loop->watchers = watchers; loop->nwatchers = nwatchers; + return 0; } void uv__io_init(uv__io_t* w, uv__io_cb cb, int fd) { - assert(cb != NULL); assert(fd >= -1); uv__queue_init(&w->pending_queue); uv__queue_init(&w->watcher_queue); @@ -912,14 +914,18 @@ void uv__io_init(uv__io_t* w, uv__io_cb cb, int fd) { } -void uv__io_start(uv_loop_t* loop, uv__io_t* w, unsigned int events) { +int uv__io_start(uv_loop_t* loop, uv__io_t* w, unsigned int events) { + int err; + assert(0 == (events & ~(POLLIN | POLLOUT | UV__POLLRDHUP | UV__POLLPRI))); assert(0 != events); assert(w->fd >= 0); assert(w->fd < INT_MAX); w->pevents |= events; - maybe_resize(loop, w->fd + 1); + err = maybe_resize(loop, w->fd + 1); + if (err) + return err; #if !defined(__sun) /* The event ports backend needs to rearm all file descriptors on each and @@ -927,7 +933,7 @@ void uv__io_start(uv_loop_t* loop, uv__io_t* w, unsigned int events) { * short-circuit here if the event mask is unchanged. */ if (w->events == w->pevents) - return; + return 0; #endif if (uv__queue_empty(&w->watcher_queue)) @@ -937,6 +943,25 @@ void uv__io_start(uv_loop_t* loop, uv__io_t* w, unsigned int events) { loop->watchers[w->fd] = w; loop->nfds++; } + + return 0; +} + + +int uv__io_init_start(uv_loop_t* loop, + uv__io_t* w, + uv__io_cb cb, + int fd, + unsigned int events) { + int err; + + assert(cb != NULL); + assert(fd > -1); + uv__io_init(w, cb, fd); + err = uv__io_start(loop, w, events); + if (err) + uv__io_init(w, NULL, -1); + return err; } @@ -999,10 +1024,10 @@ int uv__fd_exists(uv_loop_t* loop, int fd) { } -int uv_getrusage(uv_rusage_t* rusage) { +static int uv__getrusage(int who, uv_rusage_t* rusage) { struct rusage usage; - if (getrusage(RUSAGE_SELF, &usage)) + if (getrusage(who, &usage)) return UV__ERR(errno); rusage->ru_utime.tv_sec = usage.ru_utime.tv_sec; @@ -1041,6 +1066,50 @@ int uv_getrusage(uv_rusage_t* rusage) { } +int uv_getrusage(uv_rusage_t* rusage) { + return uv__getrusage(RUSAGE_SELF, rusage); +} + + +int uv_getrusage_thread(uv_rusage_t* rusage) { +#if defined(__APPLE__) + mach_msg_type_number_t count; + thread_basic_info_data_t info; + kern_return_t kr; + thread_t thread; + + thread = mach_thread_self(); + count = THREAD_BASIC_INFO_COUNT; + kr = thread_info(thread, + THREAD_BASIC_INFO, + (thread_info_t)&info, + &count); + + if (kr != KERN_SUCCESS) { + mach_port_deallocate(mach_task_self(), thread); + return UV_EINVAL; + } + + memset(rusage, 0, sizeof(*rusage)); + + rusage->ru_utime.tv_sec = info.user_time.seconds; + rusage->ru_utime.tv_usec = info.user_time.microseconds; + rusage->ru_stime.tv_sec = info.system_time.seconds; + rusage->ru_stime.tv_usec = info.system_time.microseconds; + + mach_port_deallocate(mach_task_self(), thread); + + return 0; + +#elif defined(RUSAGE_LWP) + return uv__getrusage(RUSAGE_LWP, rusage); +#elif defined(RUSAGE_THREAD) + return uv__getrusage(RUSAGE_THREAD, rusage); +#endif /* defined(__APPLE__) */ + return UV_ENOTSUP; +} + + int uv__open_cloexec(const char* path, int flags) { #if defined(O_CLOEXEC) int fd; @@ -1977,14 +2046,11 @@ unsigned int uv_available_parallelism(void) { #ifdef __linux__ { - double rc_with_cgroup; - uv__cpu_constraint c = {0, 0, 0.0}; + long long quota = 0; - if (uv__get_constrained_cpu(&c) == 0 && c.period_length > 0) { - rc_with_cgroup = (double)c.quota_per_period / c.period_length * c.proportions; - if (rc_with_cgroup < rc) - rc = (long)rc_with_cgroup; /* Casting is safe since rc_with_cgroup < rc < LONG_MAX */ - } + if (uv__get_constrained_cpu("a) == 0) + if (quota > 0 && quota < rc) + rc = quota; } #endif /* __linux__ */ diff --git a/deps/uv/src/unix/darwin-proctitle.c b/deps/uv/src/unix/darwin-proctitle.c index 5288083ef04fd7..5e5642972a4df6 100644 --- a/deps/uv/src/unix/darwin-proctitle.c +++ b/deps/uv/src/unix/darwin-proctitle.c @@ -33,25 +33,9 @@ #include "darwin-stub.h" #endif - -static int uv__pthread_setname_np(const char* name) { - char namebuf[64]; /* MAXTHREADNAMESIZE */ - int err; - - strncpy(namebuf, name, sizeof(namebuf) - 1); - namebuf[sizeof(namebuf) - 1] = '\0'; - - err = pthread_setname_np(namebuf); - if (err) - return UV__ERR(err); - - return 0; -} - - int uv__set_process_title(const char* title) { #if TARGET_OS_IPHONE - return uv__pthread_setname_np(title); + return uv__thread_setname(title); #else CFStringRef (*pCFStringCreateWithCString)(CFAllocatorRef, const char*, @@ -177,7 +161,7 @@ int uv__set_process_title(const char* title) { goto out; } - uv__pthread_setname_np(title); /* Don't care if it fails. */ + uv__thread_setname(title); /* Don't care if it fails. */ err = 0; out: diff --git a/deps/uv/src/unix/fs.c b/deps/uv/src/unix/fs.c index 239ecda16a7eb9..717f3fab36939e 100644 --- a/deps/uv/src/unix/fs.c +++ b/deps/uv/src/unix/fs.c @@ -203,8 +203,23 @@ static ssize_t uv__fs_fdatasync(uv_fs_t* req) { } -UV_UNUSED(static struct timespec uv__fs_to_timespec(double time)) { +#if defined(__APPLE__) \ + || defined(_AIX71) \ + || defined(__DragonFly__) \ + || defined(__FreeBSD__) \ + || defined(__HAIKU__) \ + || defined(__NetBSD__) \ + || defined(__OpenBSD__) \ + || defined(__linux__) \ + || defined(__sun) +static struct timespec uv__fs_to_timespec(double time) { struct timespec ts; + + if (uv__isinf(time)) + return (struct timespec){UTIME_NOW, UTIME_NOW}; + if (uv__isnan(time)) + return (struct timespec){UTIME_OMIT, UTIME_OMIT}; + ts.tv_sec = time; ts.tv_nsec = (time - ts.tv_sec) * 1e9; @@ -221,41 +236,23 @@ UV_UNUSED(static struct timespec uv__fs_to_timespec(double time)) { } return ts; } +#endif -UV_UNUSED(static struct timeval uv__fs_to_timeval(double time)) { - struct timeval tv; - tv.tv_sec = time; - tv.tv_usec = (time - tv.tv_sec) * 1e6; - if (tv.tv_usec < 0) { - tv.tv_usec += 1e6; - tv.tv_sec -= 1; - } - return tv; -} static ssize_t uv__fs_futime(uv_fs_t* req) { -#if defined(__linux__) \ +#if defined(__APPLE__) \ || defined(_AIX71) \ - || defined(__HAIKU__) \ - || defined(__GNU__) - struct timespec ts[2]; - ts[0] = uv__fs_to_timespec(req->atime); - ts[1] = uv__fs_to_timespec(req->mtime); - return futimens(req->file, ts); -#elif defined(__APPLE__) \ || defined(__DragonFly__) \ || defined(__FreeBSD__) \ + || defined(__HAIKU__) \ || defined(__NetBSD__) \ || defined(__OpenBSD__) \ + || defined(__linux__) \ || defined(__sun) - struct timeval tv[2]; - tv[0] = uv__fs_to_timeval(req->atime); - tv[1] = uv__fs_to_timeval(req->mtime); -# if defined(__sun) - return futimesat(req->file, NULL, tv); -# else - return futimes(req->file, tv); -# endif + struct timespec ts[2]; + ts[0] = uv__fs_to_timespec(req->atime); + ts[1] = uv__fs_to_timespec(req->mtime); + return futimens(req->file, ts); #elif defined(__MVS__) attrib_t atr; memset(&atr, 0, sizeof(atr)); @@ -461,12 +458,7 @@ static ssize_t uv__pwritev_emul(int fd, /* The function pointer cache is an uintptr_t because _Atomic void* * doesn't work on macos/ios/etc... - * Disable optimization on armv7 to work around the bug described in - * https://github.com/libuv/libuv/issues/4532 */ -#if defined(__arm__) && (__ARM_ARCH == 7) -__attribute__((optimize("O0"))) -#endif static ssize_t uv__preadv_or_pwritev(int fd, const struct iovec* bufs, size_t nbufs, @@ -479,7 +471,12 @@ static ssize_t uv__preadv_or_pwritev(int fd, p = (void*) atomic_load_explicit(cache, memory_order_relaxed); if (p == NULL) { #ifdef RTLD_DEFAULT - p = dlsym(RTLD_DEFAULT, is_pread ? "preadv" : "pwritev"); + /* Try _LARGEFILE_SOURCE version of preadv/pwritev first, + * then fall back to the plain version, for libcs like musl. + */ + p = dlsym(RTLD_DEFAULT, is_pread ? "preadv64" : "pwritev64"); + if (p == NULL) + p = dlsym(RTLD_DEFAULT, is_pread ? "preadv" : "pwritev"); dlerror(); /* Clear errors. */ #endif /* RTLD_DEFAULT */ if (p == NULL) @@ -487,10 +484,7 @@ static ssize_t uv__preadv_or_pwritev(int fd, atomic_store_explicit(cache, (uintptr_t) p, memory_order_relaxed); } - /* Use memcpy instead of `f = p` to work around a compiler bug, - * see https://github.com/libuv/libuv/issues/4532 - */ - memcpy(&f, &p, sizeof(p)); + f = p; return f(fd, bufs, nbufs, off); } @@ -1145,25 +1139,20 @@ static ssize_t uv__fs_sendfile(uv_fs_t* req) { static ssize_t uv__fs_utime(uv_fs_t* req) { -#if defined(__linux__) \ - || defined(_AIX71) \ - || defined(__sun) \ - || defined(__HAIKU__) +#if defined(__APPLE__) \ + || defined(_AIX71) \ + || defined(__DragonFly__) \ + || defined(__FreeBSD__) \ + || defined(__HAIKU__) \ + || defined(__NetBSD__) \ + || defined(__OpenBSD__) \ + || defined(__linux__) \ + || defined(__sun) struct timespec ts[2]; ts[0] = uv__fs_to_timespec(req->atime); ts[1] = uv__fs_to_timespec(req->mtime); return utimensat(AT_FDCWD, req->path, ts, 0); -#elif defined(__APPLE__) \ - || defined(__DragonFly__) \ - || defined(__FreeBSD__) \ - || defined(__NetBSD__) \ - || defined(__OpenBSD__) - struct timeval tv[2]; - tv[0] = uv__fs_to_timeval(req->atime); - tv[1] = uv__fs_to_timeval(req->mtime); - return utimes(req->path, tv); -#elif defined(_AIX) \ - && !defined(_AIX71) +#elif defined(_AIX) && !defined(_AIX71) struct utimbuf buf; buf.actime = req->atime; buf.modtime = req->mtime; @@ -1184,24 +1173,19 @@ static ssize_t uv__fs_utime(uv_fs_t* req) { static ssize_t uv__fs_lutime(uv_fs_t* req) { -#if defined(__linux__) || \ - defined(_AIX71) || \ - defined(__sun) || \ - defined(__HAIKU__) || \ - defined(__GNU__) || \ - defined(__OpenBSD__) +#if defined(__APPLE__) \ + || defined(_AIX71) \ + || defined(__DragonFly__) \ + || defined(__FreeBSD__) \ + || defined(__HAIKU__) \ + || defined(__NetBSD__) \ + || defined(__OpenBSD__) \ + || defined(__linux__) \ + || defined(__sun) struct timespec ts[2]; ts[0] = uv__fs_to_timespec(req->atime); ts[1] = uv__fs_to_timespec(req->mtime); return utimensat(AT_FDCWD, req->path, ts, AT_SYMLINK_NOFOLLOW); -#elif defined(__APPLE__) || \ - defined(__DragonFly__) || \ - defined(__FreeBSD__) || \ - defined(__NetBSD__) - struct timeval tv[2]; - tv[0] = uv__fs_to_timeval(req->atime); - tv[1] = uv__fs_to_timeval(req->mtime); - return lutimes(req->path, tv); #else errno = ENOSYS; return -1; diff --git a/deps/uv/src/unix/haiku.c b/deps/uv/src/unix/haiku.c index 31284b66dc3e96..0d3645f014b4eb 100644 --- a/deps/uv/src/unix/haiku.c +++ b/deps/uv/src/unix/haiku.c @@ -120,7 +120,7 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { int i; status_t status; system_info system; - uint32_t topology_count; + uint32 topology_count; /* Haiku expects address of uint32, not uint32_t */ uint64_t cpuspeed; uv_cpu_info_t* cpu_info; diff --git a/deps/uv/src/unix/ibmi.c b/deps/uv/src/unix/ibmi.c index 837bba6e2fef7b..9d94d2af54468a 100644 --- a/deps/uv/src/unix/ibmi.c +++ b/deps/uv/src/unix/ibmi.c @@ -394,6 +394,8 @@ static int get_ibmi_physical_address(const char* line, char (*phys_addr)[6]) { int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { uv_interface_address_t* address; struct ifaddrs_pase *ifap = NULL, *cur; + size_t namelen; + char* name; int inet6, r = 0; *count = 0; @@ -403,6 +405,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { return UV_ENOSYS; /* The first loop to get the size of the array to be allocated */ + namelen = 0; for (cur = ifap; cur; cur = cur->ifa_next) { if (!(cur->ifa_addr->sa_family == AF_INET6 || cur->ifa_addr->sa_family == AF_INET)) @@ -411,6 +414,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { if (!(cur->ifa_flags & IFF_UP && cur->ifa_flags & IFF_RUNNING)) continue; + namelen += strlen(cur->ifa_name) + 1; (*count)++; } @@ -420,11 +424,13 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { } /* Alloc the return interface structs */ - *addresses = uv__calloc(*count, sizeof(**addresses)); + *addresses = uv__calloc(1, *count * sizeof(**addresses) + namelen); if (*addresses == NULL) { Qp2freeifaddrs(ifap); return UV_ENOMEM; } + + name = (char*) &(*addresses)[*count]; address = *addresses; /* The second loop to fill in the array */ @@ -436,7 +442,9 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { if (!(cur->ifa_flags & IFF_UP && cur->ifa_flags & IFF_RUNNING)) continue; - address->name = uv__strdup(cur->ifa_name); + namelen = strlen(cur->ifa_name) + 1; + address->name = memcpy(name, cur->ifa_name, namelen); + name += namelen; inet6 = (cur->ifa_addr->sa_family == AF_INET6); @@ -497,13 +505,8 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { } -void uv_free_interface_addresses(uv_interface_address_t* addresses, int count) { - int i; - - for (i = 0; i < count; ++i) { - uv__free(addresses[i].name); - } - +void uv_free_interface_addresses(uv_interface_address_t* addresses, + int count) { uv__free(addresses); } diff --git a/deps/uv/src/unix/internal.h b/deps/uv/src/unix/internal.h index 8d586b0b64a96c..a1d7d4366308ac 100644 --- a/deps/uv/src/unix/internal.h +++ b/deps/uv/src/unix/internal.h @@ -35,6 +35,10 @@ #include #include #include +#if defined(__APPLE__) || defined(__DragonFly__) || \ + defined(__FreeBSD__) || defined(__NetBSD__) +#include +#endif #define uv__msan_unpoison(p, n) \ do { \ @@ -253,7 +257,12 @@ void uv__make_close_pending(uv_handle_t* handle); int uv__getiovmax(void); void uv__io_init(uv__io_t* w, uv__io_cb cb, int fd); -void uv__io_start(uv_loop_t* loop, uv__io_t* w, unsigned int events); +int uv__io_start(uv_loop_t* loop, uv__io_t* w, unsigned int events); +int uv__io_init_start(uv_loop_t* loop, + uv__io_t* w, + uv__io_cb cb, + int fd, + unsigned int events); void uv__io_stop(uv_loop_t* loop, uv__io_t* w, unsigned int events); void uv__io_close(uv_loop_t* loop, uv__io_t* w); void uv__io_feed(uv_loop_t* loop, uv__io_t* w); @@ -323,6 +332,8 @@ void uv__prepare_close(uv_prepare_t* handle); void uv__process_close(uv_process_t* handle); void uv__stream_close(uv_stream_t* handle); void uv__tcp_close(uv_tcp_t* handle); +int uv__thread_setname(const char* name); +int uv__thread_getname(uv_thread_t* tid, char* name, size_t size); size_t uv__thread_stack_size(void); void uv__udp_close(uv_udp_t* handle); void uv__udp_finish_close(uv_udp_t* handle); @@ -483,13 +494,7 @@ uv__fs_copy_file_range(int fd_in, #endif #ifdef __linux__ -typedef struct { - long long quota_per_period; - long long period_length; - double proportions; -} uv__cpu_constraint; - -int uv__get_constrained_cpu(uv__cpu_constraint* constraint); +int uv__get_constrained_cpu(long long* quota); #endif #if defined(__sun) && !defined(__illumos__) @@ -504,4 +509,22 @@ int uv__get_constrained_cpu(uv__cpu_constraint* constraint); #endif #endif +#if defined(EVFILT_USER) && defined(NOTE_TRIGGER) +/* EVFILT_USER is available since OS X 10.6, DragonFlyBSD 4.0, + * FreeBSD 8.1, and NetBSD 10.0. + * + * Note that even though EVFILT_USER is defined on the current system, + * it may still fail to work at runtime somehow. In that case, we fall + * back to pipe-based signaling. + */ +#define UV__KQUEUE_EVFILT_USER 1 +/* Magic number of identifier used for EVFILT_USER during runtime detection. + * There are no Google hits for this number when I create it. That way, + * people will be directed here if this number gets printed due to some + * kqueue error and they google for help. */ +#define UV__KQUEUE_EVFILT_USER_IDENT 0x1e7e7711 +#else +#define UV__KQUEUE_EVFILT_USER 0 +#endif + #endif /* UV_UNIX_INTERNAL_H_ */ diff --git a/deps/uv/src/unix/kqueue.c b/deps/uv/src/unix/kqueue.c index 66aa166f053f52..39b72012c26955 100644 --- a/deps/uv/src/unix/kqueue.c +++ b/deps/uv/src/unix/kqueue.c @@ -97,8 +97,7 @@ int uv__io_fork(uv_loop_t* loop) { int uv__io_check_fd(uv_loop_t* loop, int fd) { - struct kevent ev; - int rc; + struct kevent ev[2]; struct stat sb; #ifdef __APPLE__ char path[MAXPATHLEN]; @@ -133,17 +132,12 @@ int uv__io_check_fd(uv_loop_t* loop, int fd) { } #endif - rc = 0; - EV_SET(&ev, fd, EVFILT_READ, EV_ADD, 0, 0, 0); - if (kevent(loop->backend_fd, &ev, 1, NULL, 0, NULL)) - rc = UV__ERR(errno); - - EV_SET(&ev, fd, EVFILT_READ, EV_DELETE, 0, 0, 0); - if (rc == 0) - if (kevent(loop->backend_fd, &ev, 1, NULL, 0, NULL)) - abort(); + EV_SET(ev, fd, EVFILT_READ, EV_ADD, 0, 0, 0); + EV_SET(ev + 1, fd, EVFILT_READ, EV_DELETE, 0, 0, 0); + if (kevent(loop->backend_fd, ev, 2, NULL, 0, NULL)) + return UV__ERR(errno); - return rc; + return 0; } @@ -367,6 +361,17 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { continue; } +#if UV__KQUEUE_EVFILT_USER + if (ev->filter == EVFILT_USER) { + w = &loop->async_io_watcher; + assert(fd == w->fd); + uv__metrics_update_idle_time(loop); + w->cb(loop, w, w->events); + nevents++; + continue; + } +#endif + if (ev->filter == EVFILT_VNODE) { assert(w->events == POLLIN); assert(w->pevents == POLLIN); @@ -564,6 +569,7 @@ int uv_fs_event_start(uv_fs_event_t* handle, const char* path, unsigned int flags) { int fd; + int r; #if defined(__APPLE__) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 struct stat statbuf; #endif @@ -599,7 +605,6 @@ int uv_fs_event_start(uv_fs_event_t* handle, if (0 == atomic_load_explicit(&uv__has_forked_with_cfrunloop, memory_order_relaxed)) { - int r; /* The fallback fd is no longer needed */ uv__close_nocheckstdio(fd); handle->event_watcher.fd = -1; @@ -615,11 +620,16 @@ int uv_fs_event_start(uv_fs_event_t* handle, fallback: #endif /* #if defined(__APPLE__) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 */ - uv__handle_start(handle); - uv__io_init(&handle->event_watcher, uv__fs_event, fd); - uv__io_start(handle->loop, &handle->event_watcher, POLLIN); + r = uv__io_init_start(handle->loop, + &handle->event_watcher, + uv__fs_event, + fd, + POLLIN); - return 0; + if (!r) + uv__handle_start(handle); + + return r; } diff --git a/deps/uv/src/unix/linux.c b/deps/uv/src/unix/linux.c index 857a4ef8a6686f..ea3e2de0384b2c 100644 --- a/deps/uv/src/unix/linux.c +++ b/deps/uv/src/unix/linux.c @@ -455,7 +455,7 @@ int uv__io_uring_register(int fd, unsigned opcode, void* arg, unsigned nargs) { } -static int uv__use_io_uring(void) { +static int uv__use_io_uring(uint32_t flags) { #if defined(__ANDROID_API__) return 0; /* Possibly available but blocked by seccomp. */ #elif defined(__arm__) && __SIZEOF_POINTER__ == 4 @@ -470,25 +470,27 @@ static int uv__use_io_uring(void) { char* val; int use; - use = atomic_load_explicit(&use_io_uring, memory_order_relaxed); - - if (use == 0) { - use = uv__kernel_version() >= #if defined(__hppa__) - /* io_uring first supported on parisc in 6.1, functional in .51 */ - /* https://lore.kernel.org/all/cb912694-b1fe-dbb0-4d8c-d608f3526905@gmx.de/ */ - /* 6.1.51 */ 0x060133 -#else - /* Older kernels have a bug where the sqpoll thread uses 100% CPU. */ - /* 5.10.186 */ 0x050ABA + /* io_uring first supported on parisc in 6.1, functional in .51 + * https://lore.kernel.org/all/cb912694-b1fe-dbb0-4d8c-d608f3526905@gmx.de/ + */ + if (uv__kernel_version() < /*6.1.51*/0x060133) + return 0; #endif - ? 1 : -1; - /* But users can still enable it if they so desire. */ - val = getenv("UV_USE_IO_URING"); - if (val != NULL) - use = atoi(val) ? 1 : -1; + /* SQPOLL is all kinds of buggy but epoll batching should work fine. */ + if (0 == (flags & UV__IORING_SETUP_SQPOLL)) + return 1; + /* Older kernels have a bug where the sqpoll thread uses 100% CPU. */ + if (uv__kernel_version() < /*5.10.186*/0x050ABA) + return 0; + + use = atomic_load_explicit(&use_io_uring, memory_order_relaxed); + + if (use == 0) { + val = getenv("UV_USE_IO_URING"); + use = val != NULL && atoi(val) > 0 ? 1 : -1; atomic_store_explicit(&use_io_uring, use, memory_order_relaxed); } @@ -518,7 +520,7 @@ static void uv__iou_init(int epollfd, sq = MAP_FAILED; sqe = MAP_FAILED; - if (!uv__use_io_uring()) + if (!uv__use_io_uring(flags)) return; kernel_version = uv__kernel_version(); @@ -766,14 +768,13 @@ static struct uv__io_uring_sqe* uv__iou_get_sqe(struct uv__iou* iou, */ if (iou->ringfd == -2) { /* By default, the SQPOLL is not created. Enable only if the loop is - * configured with UV_LOOP_USE_IO_URING_SQPOLL. + * configured with UV_LOOP_USE_IO_URING_SQPOLL and the UV_USE_IO_URING + * environment variable is unset or a positive number. */ - if ((loop->flags & UV_LOOP_ENABLE_IO_URING_SQPOLL) == 0) { - iou->ringfd = -1; - return NULL; - } + if (loop->flags & UV_LOOP_ENABLE_IO_URING_SQPOLL) + if (uv__use_io_uring(UV__IORING_SETUP_SQPOLL)) + uv__iou_init(loop->backend_fd, iou, 64, UV__IORING_SETUP_SQPOLL); - uv__iou_init(loop->backend_fd, iou, 64, UV__IORING_SETUP_SQPOLL); if (iou->ringfd == -2) iou->ringfd = -1; /* "failed" */ } @@ -1713,16 +1714,22 @@ int uv_uptime(double* uptime) { int uv_cpu_info(uv_cpu_info_t** ci, int* count) { #if defined(__PPC__) static const char model_marker[] = "cpu\t\t: "; + static const char model_marker2[] = ""; #elif defined(__arm__) - static const char model_marker[] = "Processor\t: "; + static const char model_marker[] = "model name\t: "; + static const char model_marker2[] = "Processor\t: "; #elif defined(__aarch64__) static const char model_marker[] = "CPU part\t: "; + static const char model_marker2[] = ""; #elif defined(__mips__) static const char model_marker[] = "cpu model\t\t: "; + static const char model_marker2[] = ""; #elif defined(__loongarch__) static const char model_marker[] = "cpu family\t\t: "; + static const char model_marker2[] = ""; #else static const char model_marker[] = "model name\t: "; + static const char model_marker2[] = ""; #endif static const char parts[] = #ifdef __aarch64__ @@ -1821,14 +1828,22 @@ int uv_cpu_info(uv_cpu_info_t** ci, int* count) { if (1 != fscanf(fp, "processor\t: %u\n", &cpu)) break; /* Parse error. */ - found = 0; - while (!found && fgets(buf, sizeof(buf), fp)) - found = !strncmp(buf, model_marker, sizeof(model_marker) - 1); + while (fgets(buf, sizeof(buf), fp)) { + if (!strncmp(buf, model_marker, sizeof(model_marker) - 1)) { + p = buf + sizeof(model_marker) - 1; + goto parts; + } + if (!*model_marker2) + continue; + if (!strncmp(buf, model_marker2, sizeof(model_marker2) - 1)) { + p = buf + sizeof(model_marker2) - 1; + goto parts; + } + } - if (!found) - goto next; + goto next; /* Not found. */ - p = buf + sizeof(model_marker) - 1; +parts: n = (int) strcspn(p, "\n"); /* arm64: translate CPU part code to model name. */ @@ -1939,11 +1954,15 @@ static int uv__ifaddr_exclude(struct ifaddrs *ent, int exclude_type) { return !exclude_type; } +/* TODO(bnoordhuis) share with bsd-ifaddrs.c */ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { - struct ifaddrs *addrs, *ent; uv_interface_address_t* address; + struct sockaddr_ll* sll; + struct ifaddrs* addrs; + struct ifaddrs* ent; + size_t namelen; + char* name; int i; - struct sockaddr_ll *sll; *count = 0; *addresses = NULL; @@ -1952,10 +1971,12 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { return UV__ERR(errno); /* Count the number of interfaces */ + namelen = 0; for (ent = addrs; ent != NULL; ent = ent->ifa_next) { if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFADDR)) continue; + namelen += strlen(ent->ifa_name) + 1; (*count)++; } @@ -1965,19 +1986,22 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { } /* Make sure the memory is initiallized to zero using calloc() */ - *addresses = uv__calloc(*count, sizeof(**addresses)); - if (!(*addresses)) { + *addresses = uv__calloc(1, *count * sizeof(**addresses) + namelen); + if (*addresses == NULL) { freeifaddrs(addrs); return UV_ENOMEM; } + name = (char*) &(*addresses)[*count]; address = *addresses; for (ent = addrs; ent != NULL; ent = ent->ifa_next) { if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFADDR)) continue; - address->name = uv__strdup(ent->ifa_name); + namelen = strlen(ent->ifa_name) + 1; + address->name = memcpy(name, ent->ifa_name, namelen); + name += namelen; if (ent->ifa_addr->sa_family == AF_INET6) { address->address.address6 = *((struct sockaddr_in6*) ent->ifa_addr); @@ -2021,14 +2045,9 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { } +/* TODO(bnoordhuis) share with bsd-ifaddrs.c */ void uv_free_interface_addresses(uv_interface_address_t* addresses, - int count) { - int i; - - for (i = 0; i < count; i++) { - uv__free(addresses[i].name); - } - + int count) { uv__free(addresses); } @@ -2286,49 +2305,83 @@ uint64_t uv_get_available_memory(void) { static int uv__get_cgroupv2_constrained_cpu(const char* cgroup, - uv__cpu_constraint* constraint) { - char path[256]; - char buf[1024]; - unsigned int weight; - int cgroup_size; + long long* quota) { + static const char cgroup_mount[] = "/sys/fs/cgroup"; const char* cgroup_trimmed; + char buf[1024]; + char full_path[256]; + char path[256]; char quota_buf[16]; + char* last_slash; + int cgroup_size; + long long limit; + long long min_quota; + long long period; if (strncmp(cgroup, "0::/", 4) != 0) return UV_EINVAL; /* Trim ending \n by replacing it with a 0 */ cgroup_trimmed = cgroup + sizeof("0::/") - 1; /* Skip the prefix "0::/" */ - cgroup_size = (int)strcspn(cgroup_trimmed, "\n"); /* Find the first slash */ + cgroup_size = (int)strcspn(cgroup_trimmed, "\n"); /* Find the first \n */ + min_quota = LLONG_MAX; - /* Construct the path to the cpu.max file */ - snprintf(path, sizeof(path), "/sys/fs/cgroup/%.*s/cpu.max", cgroup_size, - cgroup_trimmed); + /* Construct the path to the cpu.max files */ + snprintf(path, sizeof(path), "%s/%.*s/cgroup.controllers", cgroup_mount, + cgroup_size, cgroup_trimmed); - /* Read cpu.max */ + /* Read controllers, if not exists, not really a cgroup */ if (uv__slurp(path, buf, sizeof(buf)) < 0) return UV_EIO; - if (sscanf(buf, "%15s %llu", quota_buf, &constraint->period_length) != 2) - return UV_EINVAL; + snprintf(path, sizeof(path), "%s/%.*s", cgroup_mount, cgroup_size, + cgroup_trimmed); - if (strncmp(quota_buf, "max", 3) == 0) - constraint->quota_per_period = LLONG_MAX; - else if (sscanf(quota_buf, "%lld", &constraint->quota_per_period) != 1) - return UV_EINVAL; // conversion failed + /* + * Traverse up the cgroup v2 hierarchy, starting from the current cgroup path. + * At each level, attempt to read the "cpu.max" file, which defines the CPU + * quota and period. + * + * This reflects how Linux applies cgroup limits hierarchically. + * + * e.g: given a path like /sys/fs/cgroup/foo/bar/baz, we check: + * - /sys/fs/cgroup/foo/bar/baz/cpu.max + * - /sys/fs/cgroup/foo/bar/cpu.max + * - /sys/fs/cgroup/foo/cpu.max + * - /sys/fs/cgroup/cpu.max + */ + while (strncmp(path, cgroup_mount, strlen(cgroup_mount)) == 0) { + snprintf(full_path, sizeof(full_path), "%s/cpu.max", path); - /* Construct the path to the cpu.weight file */ - snprintf(path, sizeof(path), "/sys/fs/cgroup/%.*s/cpu.weight", cgroup_size, - cgroup_trimmed); + /* Silently ignore and continue if the file does not exist */ + if (uv__slurp(full_path, quota_buf, sizeof(quota_buf)) < 0) + goto next; - /* Read cpu.weight */ - if (uv__slurp(path, buf, sizeof(buf)) < 0) - return UV_EIO; + /* No limit, move on */ + if (strncmp(quota_buf, "max", 3) == 0) + goto next; - if (sscanf(buf, "%u", &weight) != 1) - return UV_EINVAL; + /* Read cpu.max */ + if (sscanf(quota_buf, "%lld %lld", &limit, &period) != 2) + goto next; - constraint->proportions = (double)weight / 100.0; + /* Can't divide by 0 */ + if (period == 0) + goto next; + + *quota = limit / period; + if (*quota < min_quota) + min_quota = *quota; + +next: + /* Move up one level in the cgroup hierarchy by trimming the last path. + * The loop ends once we reach the cgroup root mount point. + */ + last_slash = strrchr(path, '/'); + if (last_slash == NULL || strcmp(path, cgroup_mount) == 0) + break; + *last_slash = '\0'; + } return 0; } @@ -2349,12 +2402,13 @@ static char* uv__cgroup1_find_cpu_controller(const char* cgroup, } static int uv__get_cgroupv1_constrained_cpu(const char* cgroup, - uv__cpu_constraint* constraint) { + long long* quota) { char path[256]; char buf[1024]; - unsigned int shares; int cgroup_size; char* cgroup_cpu; + long long period_length; + long long quota_per_period; cgroup_cpu = uv__cgroup1_find_cpu_controller(cgroup, &cgroup_size); @@ -2365,10 +2419,11 @@ static int uv__get_cgroupv1_constrained_cpu(const char* cgroup, snprintf(path, sizeof(path), "/sys/fs/cgroup/%.*s/cpu.cfs_quota_us", cgroup_size, cgroup_cpu); + /* Read cpu.cfs_quota_us */ if (uv__slurp(path, buf, sizeof(buf)) < 0) return UV_EIO; - if (sscanf(buf, "%lld", &constraint->quota_per_period) != 1) + if (sscanf(buf, "%lld", "a_per_period) != 1) return UV_EINVAL; /* Construct the path to the cpu.cfs_period_us file */ @@ -2379,26 +2434,19 @@ static int uv__get_cgroupv1_constrained_cpu(const char* cgroup, if (uv__slurp(path, buf, sizeof(buf)) < 0) return UV_EIO; - if (sscanf(buf, "%lld", &constraint->period_length) != 1) + if (sscanf(buf, "%lld", &period_length) != 1) return UV_EINVAL; - /* Construct the path to the cpu.shares file */ - snprintf(path, sizeof(path), "/sys/fs/cgroup/%.*s/cpu.shares", cgroup_size, - cgroup_cpu); - - /* Read cpu.shares */ - if (uv__slurp(path, buf, sizeof(buf)) < 0) - return UV_EIO; - - if (sscanf(buf, "%u", &shares) != 1) + /* Can't divide by 0 */ + if (period_length == 0) return UV_EINVAL; - constraint->proportions = (double)shares / 1024.0; + *quota = quota_per_period / period_length; return 0; } -int uv__get_constrained_cpu(uv__cpu_constraint* constraint) { +int uv__get_constrained_cpu(long long* quota) { char cgroup[1024]; /* Read the cgroup from /proc/self/cgroup */ @@ -2409,9 +2457,9 @@ int uv__get_constrained_cpu(uv__cpu_constraint* constraint) { * The entry for cgroup v2 is always in the format "0::$PATH" * see https://docs.kernel.org/admin-guide/cgroup-v2.html */ if (strncmp(cgroup, "0::/", 4) == 0) - return uv__get_cgroupv2_constrained_cpu(cgroup, constraint); + return uv__get_cgroupv2_constrained_cpu(cgroup, quota); else - return uv__get_cgroupv1_constrained_cpu(cgroup, constraint); + return uv__get_cgroupv1_constrained_cpu(cgroup, quota); } @@ -2441,6 +2489,7 @@ static int compare_watchers(const struct watcher_list* a, static int init_inotify(uv_loop_t* loop) { + int err; int fd; if (loop->inotify_fd != -1) @@ -2450,10 +2499,14 @@ static int init_inotify(uv_loop_t* loop) { if (fd < 0) return UV__ERR(errno); - loop->inotify_fd = fd; - uv__io_init(&loop->inotify_read_watcher, uv__inotify_read, loop->inotify_fd); - uv__io_start(loop, &loop->inotify_read_watcher, POLLIN); + err = uv__io_init_start(loop, &loop->inotify_read_watcher, uv__inotify_read, + fd, POLLIN); + if (err) { + uv__close(fd); + return err; + } + loop->inotify_fd = fd; return 0; } diff --git a/deps/uv/src/unix/loop.c b/deps/uv/src/unix/loop.c index 179ee999d8052e..5d3f0c7a348b33 100644 --- a/deps/uv/src/unix/loop.c +++ b/deps/uv/src/unix/loop.c @@ -32,12 +32,11 @@ int uv_loop_init(uv_loop_t* loop) { void* saved_data; int err; - saved_data = loop->data; memset(loop, 0, sizeof(*loop)); loop->data = saved_data; - lfields = (uv__loop_internal_fields_t*) uv__calloc(1, sizeof(*lfields)); + lfields = uv__calloc(1, sizeof(*lfields)); if (lfields == NULL) return UV_ENOMEM; loop->internal_fields = lfields; @@ -116,6 +115,11 @@ int uv_loop_init(uv_loop_t* loop) { fail_signal_init: uv__platform_loop_delete(loop); + if (loop->backend_fd != -1) { + uv__close(loop->backend_fd); + loop->backend_fd = -1; + } + fail_platform_init: uv_mutex_destroy(&lfields->loop_metrics.lock); diff --git a/deps/uv/src/unix/openbsd.c b/deps/uv/src/unix/openbsd.c index 9c863b6c90dad9..cf20fa6658209d 100644 --- a/deps/uv/src/unix/openbsd.c +++ b/deps/uv/src/unix/openbsd.c @@ -211,8 +211,16 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { which[1] = HW_CPUSPEED; size = sizeof(cpuspeed); - if (sysctl(which, ARRAY_SIZE(which), &cpuspeed, &size, NULL, 0)) + cpuspeed = 0; + /* + * HW_CPUSPEED can return EOPNOTSUPP if cpuspeed is 0, + * so ignore that and continue the flow, because we + * still care about the rest of the CPU info. + */ + if (sysctl(which, ARRAY_SIZE(which), &cpuspeed, &size, NULL, 0) && + (errno != EOPNOTSUPP)) { goto error; + } size = sizeof(info); for (i = 0; i < numcpus; i++) { diff --git a/deps/uv/src/unix/pipe.c b/deps/uv/src/unix/pipe.c index 1f9acfac41e9c5..68e225e2e17fbb 100644 --- a/deps/uv/src/unix/pipe.c +++ b/deps/uv/src/unix/pipe.c @@ -31,13 +31,15 @@ /* Does the file path contain embedded nul bytes? */ -static int includes_nul(const char *s, size_t n) { +static int includes_invalid_nul(const char *s, size_t n) { if (n == 0) return 0; #ifdef __linux__ - /* Accept abstract socket namespace path ("\0/virtual/path"). */ - s++; - n--; + /* Accept abstract socket namespace paths, throughout which nul bytes have + * no special significance ("\0foo\0bar"). + */ + if (s[0] == '\0') + return 0; #endif return NULL != memchr(s, '\0', n); } @@ -84,7 +86,7 @@ int uv_pipe_bind2(uv_pipe_t* handle, return UV_EINVAL; #endif - if (includes_nul(name, namelen)) + if (includes_invalid_nul(name, namelen)) return UV_EINVAL; if (flags & UV_PIPE_NO_TRUNCATE) @@ -271,7 +273,7 @@ int uv_pipe_connect2(uv_connect_t* req, if (namelen == 0) return UV_EINVAL; - if (includes_nul(name, namelen)) + if (includes_invalid_nul(name, namelen)) return UV_EINVAL; if (flags & UV_PIPE_NO_TRUNCATE) @@ -360,6 +362,9 @@ static int uv__pipe_getsockpeername(const uv_pipe_t* handle, char* p; int err; + if (buffer == NULL || size == NULL || *size == 0) + return UV_EINVAL; + addrlen = sizeof(sa); memset(&sa, 0, addrlen); err = uv__getsockpeername((const uv_handle_t*) handle, @@ -442,13 +447,18 @@ uv_handle_type uv_pipe_pending_type(uv_pipe_t* handle) { int uv_pipe_chmod(uv_pipe_t* handle, int mode) { - unsigned desired_mode; - struct stat pipe_stat; - char* name_buffer; + char name_buffer[1 + UV__PATH_MAX]; + int desired_mode; size_t name_len; + const char* name; + int fd; int r; - if (handle == NULL || uv__stream_fd(handle) == -1) + if (handle == NULL) + return UV_EBADF; + + fd = uv__stream_fd(handle); + if (fd == -1) return UV_EBADF; if (mode != UV_READABLE && @@ -456,46 +466,32 @@ int uv_pipe_chmod(uv_pipe_t* handle, int mode) { mode != (UV_WRITABLE | UV_READABLE)) return UV_EINVAL; - /* Unfortunately fchmod does not work on all platforms, we will use chmod. */ - name_len = 0; - r = uv_pipe_getsockname(handle, NULL, &name_len); - if (r != UV_ENOBUFS) - return r; - - name_buffer = uv__malloc(name_len); - if (name_buffer == NULL) - return UV_ENOMEM; - - r = uv_pipe_getsockname(handle, name_buffer, &name_len); - if (r != 0) { - uv__free(name_buffer); - return r; - } - - /* stat must be used as fstat has a bug on Darwin */ - if (uv__stat(name_buffer, &pipe_stat) == -1) { - uv__free(name_buffer); - return -errno; - } - desired_mode = 0; if (mode & UV_READABLE) desired_mode |= S_IRUSR | S_IRGRP | S_IROTH; if (mode & UV_WRITABLE) desired_mode |= S_IWUSR | S_IWGRP | S_IWOTH; - /* Exit early if pipe already has desired mode. */ - if ((pipe_stat.st_mode & desired_mode) == desired_mode) { - uv__free(name_buffer); - return 0; - } + /* fchmod on macOS and (Free|Net|Open)BSD does not support UNIX sockets. */ + if (fchmod(fd, desired_mode)) + if (errno != EINVAL && errno != EOPNOTSUPP) + return UV__ERR(errno); - pipe_stat.st_mode |= desired_mode; + /* Fall back to chmod. */ + name_len = sizeof(name_buffer); + r = uv_pipe_getsockname(handle, name_buffer, &name_len); + if (r != 0) + return r; + name = name_buffer; - r = chmod(name_buffer, pipe_stat.st_mode); - uv__free(name_buffer); + /* On some platforms, getsockname returns an empty string, and we try with pipe_fname. */ + if (name_len == 0 && handle->pipe_fname != NULL) + name = handle->pipe_fname; - return r != -1 ? 0 : UV__ERR(errno); + if (chmod(name, desired_mode)) + return UV__ERR(errno); + + return 0; } @@ -506,7 +502,9 @@ int uv_pipe(uv_os_fd_t fds[2], int read_flags, int write_flags) { defined(__FreeBSD__) || \ defined(__OpenBSD__) || \ defined(__DragonFly__) || \ - defined(__NetBSD__) + defined(__NetBSD__) || \ + defined(__illumos__) || \ + (defined(UV__SOLARIS_11_4) && UV__SOLARIS_11_4) int flags = O_CLOEXEC; if ((read_flags & UV_NONBLOCK_PIPE) && (write_flags & UV_NONBLOCK_PIPE)) diff --git a/deps/uv/src/unix/poll.c b/deps/uv/src/unix/poll.c index 7a12e2d1488a9d..535ac6baafc6e0 100644 --- a/deps/uv/src/unix/poll.c +++ b/deps/uv/src/unix/poll.c @@ -24,7 +24,6 @@ #include #include -#include static void uv__poll_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { diff --git a/deps/uv/src/unix/process.c b/deps/uv/src/unix/process.c index f2038f2c0e823e..43e6b798458fc1 100644 --- a/deps/uv/src/unix/process.c +++ b/deps/uv/src/unix/process.c @@ -188,8 +188,12 @@ void uv__wait_children(uv_loop_t* loop) { static int uv__process_init_stdio(uv_stdio_container_t* container, int fds[2]) { int mask; int fd; + int ret; + int size; + int i; mask = UV_IGNORE | UV_CREATE_PIPE | UV_INHERIT_FD | UV_INHERIT_STREAM; + size = 64 * 1024; switch (container->flags & mask) { case UV_IGNORE: @@ -199,8 +203,17 @@ static int uv__process_init_stdio(uv_stdio_container_t* container, int fds[2]) { assert(container->data.stream != NULL); if (container->data.stream->type != UV_NAMED_PIPE) return UV_EINVAL; - else - return uv_socketpair(SOCK_STREAM, 0, fds, 0, 0); + else { + ret = uv_socketpair(SOCK_STREAM, 0, fds, 0, 0); + + if (ret == 0) + for (i = 0; i < 2; i++) { + setsockopt(fds[i], SOL_SOCKET, SO_RCVBUF, &size, sizeof(size)); + setsockopt(fds[i], SOL_SOCKET, SO_SNDBUF, &size, sizeof(size)); + } + } + + return ret; case UV_INHERIT_FD: case UV_INHERIT_STREAM: diff --git a/deps/uv/src/unix/signal.c b/deps/uv/src/unix/signal.c index f23c887d0d6788..ccaa72db457c59 100644 --- a/deps/uv/src/unix/signal.c +++ b/deps/uv/src/unix/signal.c @@ -259,22 +259,28 @@ static void uv__signal_unregister_handler(int signum) { static int uv__signal_loop_once_init(uv_loop_t* loop) { + int* pipefd; int err; /* Return if already initialized. */ - if (loop->signal_pipefd[0] != -1) + pipefd = loop->signal_pipefd; + if (pipefd[0] != -1) return 0; - err = uv__make_pipe(loop->signal_pipefd, UV_NONBLOCK_PIPE); + err = uv__make_pipe(pipefd, UV_NONBLOCK_PIPE); if (err) return err; - uv__io_init(&loop->signal_io_watcher, - uv__signal_event, - loop->signal_pipefd[0]); - uv__io_start(loop, &loop->signal_io_watcher, POLLIN); + err = uv__io_init_start(loop, &loop->signal_io_watcher, uv__signal_event, + pipefd[0], POLLIN); + if (err) { + uv__close(pipefd[0]); + uv__close(pipefd[1]); + pipefd[0] = -1; + pipefd[1] = -1; + } - return 0; + return err; } diff --git a/deps/uv/src/unix/sunos.c b/deps/uv/src/unix/sunos.c index 2d6bae79604e09..6c38c31aa00efa 100644 --- a/deps/uv/src/unix/sunos.c +++ b/deps/uv/src/unix/sunos.c @@ -546,8 +546,15 @@ int uv_fs_event_start(uv_fs_event_t* handle, } if (first_run) { - uv__io_init(&handle->loop->fs_event_watcher, uv__fs_event_read, portfd); - uv__io_start(handle->loop, &handle->loop->fs_event_watcher, POLLIN); + err = uv__io_init_start(handle->loop, + &handle->loop->fs_event_watcher, + uv__fs_event_read, + portfd, + POLLIN); + if (err) + uv__handle_stop(handle); + + return err; } return 0; @@ -826,6 +833,8 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { uv_interface_address_t* address; struct ifaddrs* addrs; struct ifaddrs* ent; + size_t namelen; + char* name; *count = 0; *addresses = NULL; @@ -834,9 +843,11 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { return UV__ERR(errno); /* Count the number of interfaces */ + namelen = 0; for (ent = addrs; ent != NULL; ent = ent->ifa_next) { if (uv__ifaddr_exclude(ent)) continue; + namelen += strlen(ent->ifa_name) + 1; (*count)++; } @@ -845,19 +856,22 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { return 0; } - *addresses = uv__malloc(*count * sizeof(**addresses)); - if (!(*addresses)) { + *addresses = uv__calloc(1, *count * sizeof(**addresses) + namelen); + if (*addresses == NULL) { freeifaddrs(addrs); return UV_ENOMEM; } + name = (char*) &(*addresses)[*count]; address = *addresses; for (ent = addrs; ent != NULL; ent = ent->ifa_next) { if (uv__ifaddr_exclude(ent)) continue; - address->name = uv__strdup(ent->ifa_name); + namelen = strlen(ent->ifa_name) + 1; + address->name = memcpy(name, ent->ifa_name, namelen); + name += namelen; if (ent->ifa_addr->sa_family == AF_INET6) { address->address.address6 = *((struct sockaddr_in6*) ent->ifa_addr); @@ -885,13 +899,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { #endif /* SUNOS_NO_IFADDRS */ void uv_free_interface_addresses(uv_interface_address_t* addresses, - int count) { - int i; - - for (i = 0; i < count; i++) { - uv__free(addresses[i].name); - } - + int count) { uv__free(addresses); } diff --git a/deps/uv/src/unix/thread.c b/deps/uv/src/unix/thread.c index f05e6fe0f7dd5a..34fea364aebe6d 100644 --- a/deps/uv/src/unix/thread.c +++ b/deps/uv/src/unix/thread.c @@ -23,6 +23,9 @@ #include "internal.h" #include +#ifdef __OpenBSD__ +#include +#endif #include #include @@ -126,6 +129,12 @@ int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) { return uv_thread_create_ex(tid, ¶ms, entry, arg); } + +int uv_thread_detach(uv_thread_t *tid) { + return UV__ERR(pthread_detach(*tid)); +} + + int uv_thread_create_ex(uv_thread_t* tid, const uv_thread_options_t* params, void (*entry)(void *arg), @@ -205,7 +214,7 @@ int uv_thread_setaffinity(uv_thread_t* tid, if (cpumask[i]) CPU_SET(i, &cpuset); -#if defined(__ANDROID__) +#if defined(__ANDROID__) || defined(__OHOS__) if (sched_setaffinity(pthread_gettid_np(*tid), sizeof(cpuset), &cpuset)) r = errno; else @@ -233,7 +242,7 @@ int uv_thread_getaffinity(uv_thread_t* tid, return UV_EINVAL; CPU_ZERO(&cpuset); -#if defined(__ANDROID__) +#if defined(__ANDROID__) || defined(__OHOS__) if (sched_getaffinity(pthread_gettid_np(*tid), sizeof(cpuset), &cpuset)) r = errno; else @@ -291,6 +300,18 @@ int uv_thread_equal(const uv_thread_t* t1, const uv_thread_t* t2) { return pthread_equal(*t1, *t2); } +int uv_thread_setname(const char* name) { + if (name == NULL) + return UV_EINVAL; + return uv__thread_setname(name); +} + +int uv_thread_getname(uv_thread_t* tid, char* name, size_t size) { + if (name == NULL || size == 0) + return UV_EINVAL; + + return uv__thread_getname(tid, name, size); +} int uv_mutex_init(uv_mutex_t* mutex) { #if defined(NDEBUG) || !defined(PTHREAD_MUTEX_ERRORCHECK) @@ -875,3 +896,80 @@ void uv_key_set(uv_key_t* key, void* value) { if (pthread_setspecific(*key, value)) abort(); } + +#if defined(_AIX) || defined(__MVS__) || defined(__PASE__) +int uv__thread_setname(const char* name) { + return UV_ENOSYS; +} +#elif defined(__APPLE__) +int uv__thread_setname(const char* name) { + char namebuf[UV_PTHREAD_MAX_NAMELEN_NP]; + strncpy(namebuf, name, sizeof(namebuf) - 1); + namebuf[sizeof(namebuf) - 1] = '\0'; + int err = pthread_setname_np(namebuf); + if (err) + return UV__ERR(errno); + return 0; +} +#elif defined(__NetBSD__) +int uv__thread_setname(const char* name) { + char namebuf[UV_PTHREAD_MAX_NAMELEN_NP]; + strncpy(namebuf, name, sizeof(namebuf) - 1); + namebuf[sizeof(namebuf) - 1] = '\0'; + return UV__ERR(pthread_setname_np(pthread_self(), "%s", namebuf)); +} +#elif defined(__OpenBSD__) +int uv__thread_setname(const char* name) { + char namebuf[UV_PTHREAD_MAX_NAMELEN_NP]; + strncpy(namebuf, name, sizeof(namebuf) - 1); + namebuf[sizeof(namebuf) - 1] = '\0'; + pthread_set_name_np(pthread_self(), namebuf); + return 0; +} +#else +int uv__thread_setname(const char* name) { + char namebuf[UV_PTHREAD_MAX_NAMELEN_NP]; + strncpy(namebuf, name, sizeof(namebuf) - 1); + namebuf[sizeof(namebuf) - 1] = '\0'; + return UV__ERR(pthread_setname_np(pthread_self(), namebuf)); +} +#endif + +#if (defined(__ANDROID_API__) && __ANDROID_API__ < 26) || \ + defined(_AIX) || \ + defined(__MVS__) || \ + defined(__PASE__) +int uv__thread_getname(uv_thread_t* tid, char* name, size_t size) { + return UV_ENOSYS; +} +#elif defined(__OpenBSD__) +int uv__thread_getname(uv_thread_t* tid, char* name, size_t size) { + char thread_name[UV_PTHREAD_MAX_NAMELEN_NP]; + pthread_get_name_np(*tid, thread_name, sizeof(thread_name)); + strncpy(name, thread_name, size - 1); + name[size - 1] = '\0'; + return 0; +} +#elif defined(__APPLE__) +int uv__thread_getname(uv_thread_t* tid, char* name, size_t size) { + char thread_name[UV_PTHREAD_MAX_NAMELEN_NP]; + if (pthread_getname_np(*tid, thread_name, sizeof(thread_name)) != 0) + return UV__ERR(errno); + + strncpy(name, thread_name, size - 1); + name[size - 1] = '\0'; + return 0; +} +#else +int uv__thread_getname(uv_thread_t* tid, char* name, size_t size) { + int r; + char thread_name[UV_PTHREAD_MAX_NAMELEN_NP]; + r = pthread_getname_np(*tid, thread_name, sizeof(thread_name)); + if (r != 0) + return UV__ERR(r); + + strncpy(name, thread_name, size - 1); + name[size - 1] = '\0'; + return 0; +} +#endif diff --git a/deps/uv/src/unix/tty.c b/deps/uv/src/unix/tty.c index 793054ba5a9bff..b8610720267962 100644 --- a/deps/uv/src/unix/tty.c +++ b/deps/uv/src/unix/tty.c @@ -284,6 +284,11 @@ int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) { int fd; int rc; + if (uv__is_raw_tty_mode(mode)) { + /* There is only a single raw TTY mode on UNIX. */ + mode = UV_TTY_MODE_RAW; + } + if (tty->mode == (int) mode) return 0; @@ -324,6 +329,8 @@ int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) { case UV_TTY_MODE_IO: uv__tty_make_raw(&tmp); break; + default: + UNREACHABLE(); } /* Apply changes after draining */ diff --git a/deps/uv/src/unix/udp.c b/deps/uv/src/unix/udp.c index f6640fc7231863..c4a3559d61e350 100644 --- a/deps/uv/src/unix/udp.c +++ b/deps/uv/src/unix/udp.c @@ -47,6 +47,10 @@ static void uv__udp_sendmsg(uv_udp_t* handle); static int uv__udp_maybe_deferred_bind(uv_udp_t* handle, int domain, unsigned int flags); +static int uv__udp_sendmsg1(int fd, + const uv_buf_t* bufs, + unsigned int nbufs, + const struct sockaddr* addr); void uv__udp_close(uv_udp_t* handle) { @@ -282,169 +286,6 @@ static void uv__udp_recvmsg(uv_udp_t* handle) { && handle->recv_cb != NULL); } -static void uv__udp_sendmsg_one(uv_udp_t* handle, uv_udp_send_t* req) { - struct uv__queue* q; - struct msghdr h; - ssize_t size; - - for (;;) { - memset(&h, 0, sizeof h); - if (req->addr.ss_family == AF_UNSPEC) { - h.msg_name = NULL; - h.msg_namelen = 0; - } else { - h.msg_name = &req->addr; - if (req->addr.ss_family == AF_INET6) - h.msg_namelen = sizeof(struct sockaddr_in6); - else if (req->addr.ss_family == AF_INET) - h.msg_namelen = sizeof(struct sockaddr_in); - else if (req->addr.ss_family == AF_UNIX) - h.msg_namelen = sizeof(struct sockaddr_un); - else { - assert(0 && "unsupported address family"); - abort(); - } - } - h.msg_iov = (struct iovec*) req->bufs; - h.msg_iovlen = req->nbufs; - - do - size = sendmsg(handle->io_watcher.fd, &h, 0); - while (size == -1 && errno == EINTR); - - if (size == -1) - if (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOBUFS) - return; - - req->status = (size == -1 ? UV__ERR(errno) : size); - - /* Sending a datagram is an atomic operation: either all data - * is written or nothing is (and EMSGSIZE is raised). That is - * why we don't handle partial writes. Just pop the request - * off the write queue and onto the completed queue, done. - */ - uv__queue_remove(&req->queue); - uv__queue_insert_tail(&handle->write_completed_queue, &req->queue); - uv__io_feed(handle->loop, &handle->io_watcher); - - if (uv__queue_empty(&handle->write_queue)) - return; - - q = uv__queue_head(&handle->write_queue); - req = uv__queue_data(q, uv_udp_send_t, queue); - } -} - -#if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) -static void uv__udp_sendmsg_many(uv_udp_t* handle) { - uv_udp_send_t* req; - struct mmsghdr h[20]; - struct mmsghdr* p; - struct uv__queue* q; - ssize_t npkts; - size_t pkts; - size_t i; - -write_queue_drain: - for (pkts = 0, q = uv__queue_head(&handle->write_queue); - pkts < ARRAY_SIZE(h) && q != &handle->write_queue; - ++pkts, q = uv__queue_head(q)) { - req = uv__queue_data(q, uv_udp_send_t, queue); - - p = &h[pkts]; - memset(p, 0, sizeof(*p)); - if (req->addr.ss_family == AF_UNSPEC) { - p->msg_hdr.msg_name = NULL; - p->msg_hdr.msg_namelen = 0; - } else { - p->msg_hdr.msg_name = &req->addr; - if (req->addr.ss_family == AF_INET6) - p->msg_hdr.msg_namelen = sizeof(struct sockaddr_in6); - else if (req->addr.ss_family == AF_INET) - p->msg_hdr.msg_namelen = sizeof(struct sockaddr_in); - else if (req->addr.ss_family == AF_UNIX) - p->msg_hdr.msg_namelen = sizeof(struct sockaddr_un); - else { - assert(0 && "unsupported address family"); - abort(); - } - } - h[pkts].msg_hdr.msg_iov = (struct iovec*) req->bufs; - h[pkts].msg_hdr.msg_iovlen = req->nbufs; - } - -#if defined(__APPLE__) - do - npkts = sendmsg_x(handle->io_watcher.fd, h, pkts, MSG_DONTWAIT); - while (npkts == -1 && errno == EINTR); -#else - do - npkts = sendmmsg(handle->io_watcher.fd, h, pkts, 0); - while (npkts == -1 && errno == EINTR); -#endif - - if (npkts < 1) { - if (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOBUFS) - return; - for (i = 0, q = uv__queue_head(&handle->write_queue); - i < pkts && q != &handle->write_queue; - ++i, q = uv__queue_head(&handle->write_queue)) { - req = uv__queue_data(q, uv_udp_send_t, queue); - req->status = UV__ERR(errno); - uv__queue_remove(&req->queue); - uv__queue_insert_tail(&handle->write_completed_queue, &req->queue); - } - uv__io_feed(handle->loop, &handle->io_watcher); - return; - } - - /* Safety: npkts known to be >0 below. Hence cast from ssize_t - * to size_t safe. - */ - for (i = 0, q = uv__queue_head(&handle->write_queue); - i < (size_t)npkts && q != &handle->write_queue; - ++i, q = uv__queue_head(&handle->write_queue)) { - req = uv__queue_data(q, uv_udp_send_t, queue); - req->status = req->bufs[0].len; - - /* Sending a datagram is an atomic operation: either all data - * is written or nothing is (and EMSGSIZE is raised). That is - * why we don't handle partial writes. Just pop the request - * off the write queue and onto the completed queue, done. - */ - uv__queue_remove(&req->queue); - uv__queue_insert_tail(&handle->write_completed_queue, &req->queue); - } - - /* couldn't batch everything, continue sending (jump to avoid stack growth) */ - if (!uv__queue_empty(&handle->write_queue)) - goto write_queue_drain; - - uv__io_feed(handle->loop, &handle->io_watcher); -} -#endif /* __linux__ || ____FreeBSD__ || __APPLE__ */ - -static void uv__udp_sendmsg(uv_udp_t* handle) { - struct uv__queue* q; - uv_udp_send_t* req; - - if (uv__queue_empty(&handle->write_queue)) - return; - - q = uv__queue_head(&handle->write_queue); - req = uv__queue_data(q, uv_udp_send_t, queue); - -#if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) - /* Use sendmmsg() if this send request contains more than one datagram OR - * there is more than one send request (because that automatically implies - * there is more than one datagram.) - */ - if (req->nbufs != 1 || &handle->write_queue != uv__queue_next(&req->queue)) - return uv__udp_sendmsg_many(handle); -#endif - - return uv__udp_sendmsg_one(handle, req); -} /* On the BSDs, SO_REUSEPORT implies SO_REUSEADDR but with some additional * refinements for programs that use multicast. Therefore we preferentially @@ -459,6 +300,9 @@ static void uv__udp_sendmsg(uv_udp_t* handle) { * * zOS does not support getsockname with SO_REUSEPORT option when using * AF_UNIX. + * + * Solaris 11.4: SO_REUSEPORT will not load balance when SO_REUSEADDR + * is also set, but it's not valid for every socket type. */ static int uv__sock_reuseaddr(int fd) { int yes; @@ -476,8 +320,18 @@ static int uv__sock_reuseaddr(int fd) { if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof(yes))) return UV__ERR(errno); } -#elif defined(SO_REUSEPORT) && !defined(__linux__) && !defined(__GNU__) && \ - !defined(__sun__) && !defined(__DragonFly__) && !defined(_AIX73) +#elif defined(SO_REUSEPORT) && defined(UV__SOLARIS_11_4) && UV__SOLARIS_11_4 + if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof(yes))) { + if (errno != ENOPROTOOPT) + return UV__ERR(errno); + /* Not all socket types accept SO_REUSEPORT. */ + errno = 0; + if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes))) + return UV__ERR(errno); + } +#elif defined(SO_REUSEPORT) && \ + !defined(__linux__) && !defined(__GNU__) && \ + !defined(__illumos__) && !defined(__DragonFly__) && !defined(_AIX73) if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof(yes))) return UV__ERR(errno); #else @@ -743,11 +597,11 @@ int uv__udp_send(uv_udp_send_t* req, empty_queue = (handle->send_queue_count == 0); uv__req_init(handle->loop, req, UV_UDP_SEND); - assert(addrlen <= sizeof(req->addr)); + assert(addrlen <= sizeof(req->u.storage)); if (addr == NULL) - req->addr.ss_family = AF_UNSPEC; + req->u.storage.ss_family = AF_UNSPEC; else - memcpy(&req->addr, addr, addrlen); + memcpy(&req->u.storage, addr, addrlen); req->send_cb = send_cb; req->handle = handle; req->nbufs = nbufs; @@ -790,10 +644,9 @@ int uv__udp_try_send(uv_udp_t* handle, const struct sockaddr* addr, unsigned int addrlen) { int err; - struct msghdr h; - ssize_t size; - assert(nbufs > 0); + if (nbufs < 1) + return UV_EINVAL; /* already sending a message */ if (handle->send_queue_count != 0) @@ -807,24 +660,11 @@ int uv__udp_try_send(uv_udp_t* handle, assert(handle->flags & UV_HANDLE_UDP_CONNECTED); } - memset(&h, 0, sizeof h); - h.msg_name = (struct sockaddr*) addr; - h.msg_namelen = addrlen; - h.msg_iov = (struct iovec*) bufs; - h.msg_iovlen = nbufs; - - do { - size = sendmsg(handle->io_watcher.fd, &h, 0); - } while (size == -1 && errno == EINTR); - - if (size == -1) { - if (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOBUFS) - return UV_EAGAIN; - else - return UV__ERR(errno); - } + err = uv__udp_sendmsg1(handle->io_watcher.fd, bufs, nbufs, addr); + if (err > 0) + return uv__count_bufs(bufs, nbufs); - return size; + return err; } @@ -1401,3 +1241,194 @@ int uv__udp_recv_stop(uv_udp_t* handle) { return 0; } + + +static int uv__udp_prep_pkt(struct msghdr* h, + const uv_buf_t* bufs, + const unsigned int nbufs, + const struct sockaddr* addr) { + memset(h, 0, sizeof(*h)); + h->msg_name = (void*) addr; + h->msg_iov = (void*) bufs; + h->msg_iovlen = nbufs; + if (addr == NULL) + return 0; + switch (addr->sa_family) { + case AF_INET: + h->msg_namelen = sizeof(struct sockaddr_in); + return 0; + case AF_INET6: + h->msg_namelen = sizeof(struct sockaddr_in6); + return 0; + case AF_UNIX: + h->msg_namelen = sizeof(struct sockaddr_un); + return 0; + case AF_UNSPEC: + h->msg_name = NULL; + return 0; + } + return UV_EINVAL; +} + + +static int uv__udp_sendmsg1(int fd, + const uv_buf_t* bufs, + unsigned int nbufs, + const struct sockaddr* addr) { + struct msghdr h; + int r; + + if ((r = uv__udp_prep_pkt(&h, bufs, nbufs, addr))) + return r; + + do + r = sendmsg(fd, &h, 0); + while (r == -1 && errno == EINTR); + + if (r < 0) { + r = UV__ERR(errno); + if (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOBUFS) + r = UV_EAGAIN; + return r; + } + + /* UDP sockets don't EOF so we don't have to handle r=0 specially, + * that only happens when the input was a zero-sized buffer. + */ + return 1; +} + + +static int uv__udp_sendmsgv(int fd, + unsigned int count, + uv_buf_t* bufs[/*count*/], + unsigned int nbufs[/*count*/], + struct sockaddr* addrs[/*count*/]) { + unsigned int i; + int nsent; + int r; + + r = 0; + nsent = 0; + +#if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) || \ + (defined(__sun__) && defined(MSG_WAITFORONE)) + if (count > 1) { + for (i = 0; i < count; /*empty*/) { + struct mmsghdr m[20]; + unsigned int n; + + for (n = 0; i < count && n < ARRAY_SIZE(m); i++, n++) + if ((r = uv__udp_prep_pkt(&m[n].msg_hdr, bufs[i], nbufs[i], addrs[i]))) + goto exit; + + do +#if defined(__APPLE__) + r = sendmsg_x(fd, m, n, MSG_DONTWAIT); +#else + r = sendmmsg(fd, m, n, 0); +#endif + while (r == -1 && errno == EINTR); + + if (r < 1) + goto exit; + + nsent += r; + i += r; + } + + goto exit; + } +#endif /* defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) || + * (defined(__sun__) && defined(MSG_WAITFORONE)) + */ + + for (i = 0; i < count; i++, nsent++) + if ((r = uv__udp_sendmsg1(fd, bufs[i], nbufs[i], addrs[i]))) + goto exit; /* goto to avoid unused label warning. */ + +exit: + + if (nsent > 0) + return nsent; + + if (r < 0) { + r = UV__ERR(errno); + if (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOBUFS) + r = UV_EAGAIN; + } + + return r; +} + + +static void uv__udp_sendmsg(uv_udp_t* handle) { + static const int N = 20; + struct sockaddr* addrs[N]; + unsigned int nbufs[N]; + uv_buf_t* bufs[N]; + struct uv__queue* q; + uv_udp_send_t* req; + int n; + + if (uv__queue_empty(&handle->write_queue)) + return; + +again: + n = 0; + q = uv__queue_head(&handle->write_queue); + do { + req = uv__queue_data(q, uv_udp_send_t, queue); + addrs[n] = &req->u.addr; + nbufs[n] = req->nbufs; + bufs[n] = req->bufs; + q = uv__queue_next(q); + n++; + } while (n < N && q != &handle->write_queue); + + n = uv__udp_sendmsgv(handle->io_watcher.fd, n, bufs, nbufs, addrs); + while (n > 0) { + q = uv__queue_head(&handle->write_queue); + req = uv__queue_data(q, uv_udp_send_t, queue); + req->status = uv__count_bufs(req->bufs, req->nbufs); + uv__queue_remove(&req->queue); + uv__queue_insert_tail(&handle->write_completed_queue, &req->queue); + n--; + } + + if (n == 0) { + if (uv__queue_empty(&handle->write_queue)) + goto feed; + goto again; + } + + if (n == UV_EAGAIN) + return; + + /* Register the error against first request in queue because that + * is the request that uv__udp_sendmsgv tried but failed to send, + * because if it did send any requests, it won't return an error. + */ + q = uv__queue_head(&handle->write_queue); + req = uv__queue_data(q, uv_udp_send_t, queue); + req->status = n; + uv__queue_remove(&req->queue); + uv__queue_insert_tail(&handle->write_completed_queue, &req->queue); +feed: + uv__io_feed(handle->loop, &handle->io_watcher); +} + + +int uv__udp_try_send2(uv_udp_t* handle, + unsigned int count, + uv_buf_t* bufs[/*count*/], + unsigned int nbufs[/*count*/], + struct sockaddr* addrs[/*count*/]) { + int fd; + + fd = handle->io_watcher.fd; + if (fd == -1) + return UV_EINVAL; + + return uv__udp_sendmsgv(fd, count, bufs, nbufs, addrs); +} diff --git a/deps/uv/src/uv-common.c b/deps/uv/src/uv-common.c index 2200fe3f0a41e2..60ff56b9dd7391 100644 --- a/deps/uv/src/uv-common.c +++ b/deps/uv/src/uv-common.c @@ -514,6 +514,25 @@ int uv_udp_try_send(uv_udp_t* handle, } +int uv_udp_try_send2(uv_udp_t* handle, + unsigned int count, + uv_buf_t* bufs[/*count*/], + unsigned int nbufs[/*count*/], + struct sockaddr* addrs[/*count*/], + unsigned int flags) { + if (count < 1) + return UV_EINVAL; + + if (flags != 0) + return UV_EINVAL; + + if (handle->send_queue_count > 0) + return UV_EAGAIN; + + return uv__udp_try_send2(handle, count, bufs, nbufs, addrs); +} + + int uv_udp_recv_start(uv_udp_t* handle, uv_alloc_cb alloc_cb, uv_udp_recv_cb recv_cb) { @@ -644,6 +663,9 @@ int uv_send_buffer_size(uv_handle_t* handle, int *value) { int uv_fs_event_getpath(uv_fs_event_t* handle, char* buffer, size_t* size) { size_t required_len; + if (buffer == NULL || size == NULL || *size == 0) + return UV_EINVAL; + if (!uv__is_active(handle)) { *size = 0; return UV_EINVAL; diff --git a/deps/uv/src/uv-common.h b/deps/uv/src/uv-common.h index 4baede2e506ee1..b9a8e976eefdd6 100644 --- a/deps/uv/src/uv-common.h +++ b/deps/uv/src/uv-common.h @@ -31,6 +31,7 @@ #include #include #include +#include #include "uv.h" #include "uv/tree.h" @@ -125,7 +126,7 @@ enum { /* Only used by uv_tty_t handles. */ UV_HANDLE_TTY_READABLE = 0x01000000, - UV_HANDLE_TTY_RAW = 0x02000000, + UV_HANDLE_UNUSED0 = 0x02000000, UV_HANDLE_TTY_SAVED_POSITION = 0x04000000, UV_HANDLE_TTY_SAVED_ATTRIBUTES = 0x08000000, @@ -140,6 +141,10 @@ enum { UV_HANDLE_REAP = 0x10000000 }; +static inline int uv__is_raw_tty_mode(uv_tty_mode_t m) { + return m == UV_TTY_MODE_RAW || m == UV_TTY_MODE_RAW_VT; +} + int uv__loop_configure(uv_loop_t* loop, uv_loop_option option, va_list ap); void uv__loop_close(uv_loop_t* loop); @@ -191,6 +196,12 @@ int uv__udp_try_send(uv_udp_t* handle, const struct sockaddr* addr, unsigned int addrlen); +int uv__udp_try_send2(uv_udp_t* handle, + unsigned int count, + uv_buf_t* bufs[/*count*/], + unsigned int nbufs[/*count*/], + struct sockaddr* addrs[/*count*/]); + int uv__udp_recv_start(uv_udp_t* handle, uv_alloc_cb alloccb, uv_udp_recv_cb recv_cb); @@ -428,4 +439,36 @@ struct uv__loop_internal_fields_s { #endif /* __linux__ */ }; +#if defined(_WIN32) +# define UV_PTHREAD_MAX_NAMELEN_NP 32767 +#elif defined(__APPLE__) +# define UV_PTHREAD_MAX_NAMELEN_NP 64 +#elif defined(__NetBSD__) || defined(__illumos__) +# define UV_PTHREAD_MAX_NAMELEN_NP PTHREAD_MAX_NAMELEN_NP +#elif defined (__linux__) +# define UV_PTHREAD_MAX_NAMELEN_NP 16 +#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) +# define UV_PTHREAD_MAX_NAMELEN_NP (MAXCOMLEN + 1) +#else +# define UV_PTHREAD_MAX_NAMELEN_NP 16 +#endif + +/* Open-coded so downstream users don't have to link libm. */ +static inline int uv__isinf(double d) { + uint64_t v; + + STATIC_ASSERT(sizeof(v) == sizeof(d)); + memcpy(&v, &d, sizeof(v)); + return (v << 1 >> 53) == 2047 && !(v << 12); +} + +/* Open-coded so downstream users don't have to link libm. */ +static inline int uv__isnan(double d) { + uint64_t v; + + STATIC_ASSERT(sizeof(v) == sizeof(d)); + memcpy(&v, &d, sizeof(v)); + return (v << 1 >> 53) == 2047 && !!(v << 12); +} + #endif /* UV_COMMON_H_ */ diff --git a/deps/uv/src/win/core.c b/deps/uv/src/win/core.c index e9885a0f1ff389..5f41c87ad5ed13 100644 --- a/deps/uv/src/win/core.c +++ b/deps/uv/src/win/core.c @@ -114,7 +114,7 @@ static int uv__loops_add(uv_loop_t* loop) { failed_loops_realloc: uv_mutex_unlock(&uv__loops_lock); - return ERROR_OUTOFMEMORY; + return UV_ENOMEM; } @@ -423,97 +423,6 @@ int uv_backend_timeout(const uv_loop_t* loop) { } -static void uv__poll_wine(uv_loop_t* loop, DWORD timeout) { - uv__loop_internal_fields_t* lfields; - DWORD bytes; - ULONG_PTR key; - OVERLAPPED* overlapped; - uv_req_t* req; - int repeat; - uint64_t timeout_time; - uint64_t user_timeout; - int reset_timeout; - - lfields = uv__get_internal_fields(loop); - timeout_time = loop->time + timeout; - - if (lfields->flags & UV_METRICS_IDLE_TIME) { - reset_timeout = 1; - user_timeout = timeout; - timeout = 0; - } else { - reset_timeout = 0; - } - - for (repeat = 0; ; repeat++) { - /* Only need to set the provider_entry_time if timeout != 0. The function - * will return early if the loop isn't configured with UV_METRICS_IDLE_TIME. - */ - if (timeout != 0) - uv__metrics_set_provider_entry_time(loop); - - /* Store the current timeout in a location that's globally accessible so - * other locations like uv__work_done() can determine whether the queue - * of events in the callback were waiting when poll was called. - */ - lfields->current_timeout = timeout; - - GetQueuedCompletionStatus(loop->iocp, - &bytes, - &key, - &overlapped, - timeout); - - if (reset_timeout != 0) { - if (overlapped && timeout == 0) - uv__metrics_inc_events_waiting(loop, 1); - timeout = user_timeout; - reset_timeout = 0; - } - - /* Placed here because on success the loop will break whether there is an - * empty package or not, or if GetQueuedCompletionStatus returned early then - * the timeout will be updated and the loop will run again. In either case - * the idle time will need to be updated. - */ - uv__metrics_update_idle_time(loop); - - if (overlapped) { - uv__metrics_inc_events(loop, 1); - - /* Package was dequeued */ - req = uv__overlapped_to_req(overlapped); - uv__insert_pending_req(loop, req); - - /* Some time might have passed waiting for I/O, - * so update the loop time here. - */ - uv_update_time(loop); - } else if (GetLastError() != WAIT_TIMEOUT) { - /* Serious error */ - uv_fatal_error(GetLastError(), "GetQueuedCompletionStatus"); - } else if (timeout > 0) { - /* GetQueuedCompletionStatus can occasionally return a little early. - * Make sure that the desired timeout target time is reached. - */ - uv_update_time(loop); - if (timeout_time > loop->time) { - timeout = (DWORD)(timeout_time - loop->time); - /* The first call to GetQueuedCompletionStatus should return very - * close to the target time and the second should reach it, but - * this is not stated in the documentation. To make sure a busy - * loop cannot happen, the timeout is increased exponentially - * starting on the third round. - */ - timeout += repeat ? (1 << (repeat - 1)) : 0; - continue; - } - } - break; - } -} - - static void uv__poll(uv_loop_t* loop, DWORD timeout) { uv__loop_internal_fields_t* lfields; BOOL success; @@ -553,12 +462,12 @@ static void uv__poll(uv_loop_t* loop, DWORD timeout) { */ lfields->current_timeout = timeout; - success = pGetQueuedCompletionStatusEx(loop->iocp, - overlappeds, - ARRAY_SIZE(overlappeds), - &count, - timeout, - FALSE); + success = GetQueuedCompletionStatusEx(loop->iocp, + overlappeds, + ARRAY_SIZE(overlappeds), + &count, + timeout, + FALSE); if (reset_timeout != 0) { timeout = user_timeout; @@ -566,7 +475,7 @@ static void uv__poll(uv_loop_t* loop, DWORD timeout) { } /* Placed here because on success the loop will break whether there is an - * empty package or not, or if pGetQueuedCompletionStatusEx returned early + * empty package or not, or if GetQueuedCompletionStatusEx returned early * then the timeout will be updated and the loop will run again. In either * case the idle time will need to be updated. */ @@ -647,10 +556,7 @@ int uv_run(uv_loop_t *loop, uv_run_mode mode) { uv__metrics_inc_loop_count(loop); - if (pGetQueuedCompletionStatusEx) - uv__poll(loop, timeout); - else - uv__poll_wine(loop, timeout); + uv__poll(loop, timeout); /* Process immediate callbacks (e.g. write_cb) a small fixed number of * times to avoid loop starvation.*/ diff --git a/deps/uv/src/win/fs-event.c b/deps/uv/src/win/fs-event.c index 7ab407e05345f9..1bbb8c52be2d82 100644 --- a/deps/uv/src/win/fs-event.c +++ b/deps/uv/src/win/fs-event.c @@ -253,6 +253,8 @@ int uv_fs_event_start(uv_fs_event_t* handle, } dir_to_watch = dir; + uv__free(short_path); + short_path = NULL; uv__free(pathw); pathw = NULL; } @@ -577,6 +579,8 @@ void uv__process_fs_event_req(uv_loop_t* loop, uv_req_t* req, info.DeletePending) { uv__convert_utf16_to_utf8(handle->dirw, -1, &filename); handle->cb(handle, filename, UV_RENAME, 0); + uv__free(filename); + filename = NULL; } else { handle->cb(handle, NULL, 0, uv_translate_sys_error(err)); } diff --git a/deps/uv/src/win/fs.c b/deps/uv/src/win/fs.c index f2215bb3082178..27248f644f381b 100644 --- a/deps/uv/src/win/fs.c +++ b/deps/uv/src/win/fs.c @@ -58,6 +58,19 @@ #define FILE_DISPOSITION_IGNORE_READONLY_ATTRIBUTE 0x0010 #endif /* FILE_DISPOSITION_IGNORE_READONLY_ATTRIBUTE */ +NTSTATUS uv__RtlUnicodeStringInit( + PUNICODE_STRING DestinationString, + PWSTR SourceString, + size_t SourceStringLen +) { + if (SourceStringLen > 0x7FFF) + return STATUS_INVALID_PARAMETER; + DestinationString->MaximumLength = DestinationString->Length = + SourceStringLen * sizeof(SourceString[0]); + DestinationString->Buffer = SourceString; + return STATUS_SUCCESS; +} + #define INIT(subtype) \ do { \ if (req == NULL) \ @@ -1689,12 +1702,12 @@ INLINE static fs__stat_path_return_t fs__stat_path(WCHAR* path, uv_stat_t* statbuf, int do_lstat) { FILE_STAT_BASIC_INFORMATION stat_info; - // Check if the new fast API is available. + /* Check if the new fast API is available. */ if (!pGetFileInformationByName) { return FS__STAT_PATH_TRY_SLOW; } - // Check if the API call fails. + /* Check if the API call fails. */ if (!pGetFileInformationByName(path, FileStatBasicByNameInfo, &stat_info, sizeof(stat_info))) { switch(GetLastError()) { @@ -1708,7 +1721,7 @@ INLINE static fs__stat_path_return_t fs__stat_path(WCHAR* path, return FS__STAT_PATH_TRY_SLOW; } - // A file handle is needed to get st_size for links. + /* A file handle is needed to get st_size for links. */ if ((stat_info.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) { return FS__STAT_PATH_TRY_SLOW; } @@ -1775,7 +1788,7 @@ INLINE static int fs__stat_handle(HANDLE handle, uv_stat_t* statbuf, SetLastError(pRtlNtStatusToDosError(nt_status)); return -1; } else { - stat_info.VolumeSerialNumber.QuadPart = volume_info.VolumeSerialNumber; + stat_info.VolumeSerialNumber.LowPart = volume_info.VolumeSerialNumber; } stat_info.DeviceType = device_info.DeviceType; @@ -1802,7 +1815,6 @@ INLINE static int fs__stat_handle(HANDLE handle, uv_stat_t* statbuf, * detect this failure and retry without do_lstat if appropriate. */ if (fs__readlink_handle(handle, NULL, &target_length) != 0) { - fs__stat_assign_statbuf(statbuf, stat_info, do_lstat); return -1; } stat_info.EndOfFile.QuadPart = target_length; @@ -1827,7 +1839,7 @@ INLINE static void fs__stat_assign_statbuf_null(uv_stat_t* statbuf) { INLINE static void fs__stat_assign_statbuf(uv_stat_t* statbuf, FILE_STAT_BASIC_INFORMATION stat_info, int do_lstat) { - statbuf->st_dev = stat_info.VolumeSerialNumber.QuadPart; + statbuf->st_dev = stat_info.VolumeSerialNumber.LowPart; /* Todo: st_mode should probably always be 0666 for everyone. We might also * want to report 0777 if the file is a .exe or a directory. @@ -1941,6 +1953,179 @@ INLINE static void fs__stat_prepare_path(WCHAR* pathw) { } } +INLINE static DWORD fs__stat_directory(WCHAR* path, uv_stat_t* statbuf, + int do_lstat, DWORD ret_error) { + HANDLE handle = INVALID_HANDLE_VALUE; + FILE_STAT_BASIC_INFORMATION stat_info; + FILE_ID_FULL_DIR_INFORMATION dir_info; + FILE_FS_VOLUME_INFORMATION volume_info; + FILE_FS_DEVICE_INFORMATION device_info; + IO_STATUS_BLOCK io_status; + NTSTATUS nt_status; + WCHAR* path_dirpath = NULL; + WCHAR* path_filename = NULL; + UNICODE_STRING FileMask; + size_t len; + size_t split; + WCHAR splitchar; + int includes_name; + + /* AKA strtok or wcscspn, in reverse. */ + len = wcslen(path); + split = len; + + includes_name = 0; + while (split > 0 && path[split - 1] != L'\\' && path[split - 1] != L'/' && + path[split - 1] != L':') { + /* check if the path contains a character other than /,\,:,. */ + if (path[split-1] != '.') { + includes_name = 1; + } + split--; + } + /* If the path is a relative path with a file name or a folder name */ + if (split == 0 && includes_name) { + path_dirpath = L"."; + /* If there is a slash or a backslash */ + } else if (path[split - 1] == L'\\' || path[split - 1] == L'/') { + path_dirpath = path; + /* If there is no filename, consider it as a relative folder path */ + if (!includes_name) { + split = len; + /* Else, split it */ + } else { + splitchar = path[split - 1]; + path[split - 1] = L'\0'; + } + /* e.g. "..", "c:" */ + } else { + path_dirpath = path; + split = len; + } + path_filename = &path[split]; + + len = 0; + while (1) { + if (path_filename[len] == L'\0') + break; + if (path_filename[len] == L'*' || path_filename[len] == L'?' || + path_filename[len] == L'>' || path_filename[len] == L'<' || + path_filename[len] == L'"') { + ret_error = ERROR_INVALID_NAME; + goto cleanup; + } + len++; + } + + /* Get directory handle */ + handle = CreateFileW(path_dirpath, + FILE_LIST_DIRECTORY, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS, + NULL); + + if (handle == INVALID_HANDLE_VALUE) { + ret_error = GetLastError(); + goto cleanup; + } + + /* Get files in the directory */ + nt_status = uv__RtlUnicodeStringInit(&FileMask, path_filename, len); + if (!NT_SUCCESS(nt_status)) { + ret_error = pRtlNtStatusToDosError(nt_status); + goto cleanup; + } + nt_status = pNtQueryDirectoryFile(handle, + NULL, + NULL, + NULL, + &io_status, + &dir_info, + sizeof(dir_info), + FileIdFullDirectoryInformation, + TRUE, + &FileMask, + TRUE); + + /* Buffer overflow (a warning status code) is expected here since there isn't + * enough space to store the FileName, and actually indicates success. */ + if (!NT_SUCCESS(nt_status) && nt_status != STATUS_BUFFER_OVERFLOW) { + if (nt_status == STATUS_NO_MORE_FILES) + ret_error = ERROR_PATH_NOT_FOUND; + else + ret_error = pRtlNtStatusToDosError(nt_status); + goto cleanup; + } + + /* Assign values to stat_info */ + memset(&stat_info, 0, sizeof(FILE_STAT_BASIC_INFORMATION)); + stat_info.FileAttributes = dir_info.FileAttributes; + stat_info.CreationTime.QuadPart = dir_info.CreationTime.QuadPart; + stat_info.LastAccessTime.QuadPart = dir_info.LastAccessTime.QuadPart; + stat_info.LastWriteTime.QuadPart = dir_info.LastWriteTime.QuadPart; + if (stat_info.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { + /* A file handle is needed to get st_size for the link (from + * FSCTL_GET_REPARSE_POINT), which is required by posix, but we are here + * because getting the file handle failed. We could get just the + * ReparsePointTag by querying FILE_ID_EXTD_DIR_INFORMATION instead to make + * sure this really is a link before giving up here on the uv_fs_stat call, + * but that doesn't seem essential. */ + if (!do_lstat) + goto cleanup; + stat_info.EndOfFile.QuadPart = 0; + stat_info.AllocationSize.QuadPart = 0; + } else { + stat_info.EndOfFile.QuadPart = dir_info.EndOfFile.QuadPart; + stat_info.AllocationSize.QuadPart = dir_info.AllocationSize.QuadPart; + } + stat_info.ChangeTime.QuadPart = dir_info.ChangeTime.QuadPart; + stat_info.FileId.QuadPart = dir_info.FileId.QuadPart; + + /* Finish up by getting device info from the directory handle, + * since files presumably must live on their device. */ + nt_status = pNtQueryVolumeInformationFile(handle, + &io_status, + &volume_info, + sizeof volume_info, + FileFsVolumeInformation); + + /* Buffer overflow (a warning status code) is expected here. */ + if (io_status.Status == STATUS_NOT_IMPLEMENTED) { + stat_info.VolumeSerialNumber.QuadPart = 0; + } else if (NT_ERROR(nt_status)) { + ret_error = pRtlNtStatusToDosError(nt_status); + goto cleanup; + } else { + stat_info.VolumeSerialNumber.QuadPart = volume_info.VolumeSerialNumber; + } + + nt_status = pNtQueryVolumeInformationFile(handle, + &io_status, + &device_info, + sizeof device_info, + FileFsDeviceInformation); + + /* Buffer overflow (a warning status code) is expected here. */ + if (NT_ERROR(nt_status)) { + ret_error = pRtlNtStatusToDosError(nt_status); + goto cleanup; + } + + stat_info.DeviceType = device_info.DeviceType; + stat_info.NumberOfLinks = 1; /* No way to recover this info. */ + + fs__stat_assign_statbuf(statbuf, stat_info, do_lstat); + ret_error = 0; + +cleanup: + if (split != 0) + path[split - 1] = splitchar; + if (handle != INVALID_HANDLE_VALUE) + CloseHandle(handle); + return ret_error; +} INLINE static DWORD fs__stat_impl_from_path(WCHAR* path, int do_lstat, @@ -1949,7 +2134,7 @@ INLINE static DWORD fs__stat_impl_from_path(WCHAR* path, DWORD flags; DWORD ret; - // If new API exists, try to use it. + /* If new API exists, try to use it. */ switch (fs__stat_path(path, statbuf, do_lstat)) { case FS__STAT_PATH_SUCCESS: return 0; @@ -1959,7 +2144,7 @@ INLINE static DWORD fs__stat_impl_from_path(WCHAR* path, break; } - // If the new API does not exist, use the old API. + /* If the new API does not exist, use the old API. */ flags = FILE_FLAG_BACKUP_SEMANTICS; if (do_lstat) flags |= FILE_FLAG_OPEN_REPARSE_POINT; @@ -1972,8 +2157,12 @@ INLINE static DWORD fs__stat_impl_from_path(WCHAR* path, flags, NULL); - if (handle == INVALID_HANDLE_VALUE) - return GetLastError(); + if (handle == INVALID_HANDLE_VALUE) { + ret = GetLastError(); + if (ret != ERROR_ACCESS_DENIED && ret != ERROR_SHARING_VIOLATION) + return ret; + return fs__stat_directory(path, statbuf, do_lstat, ret); + } if (fs__stat_handle(handle, statbuf, do_lstat) != 0) ret = GetLastError(); @@ -2391,14 +2580,29 @@ static void fs__fchmod(uv_fs_t* req) { INLINE static int fs__utime_handle(HANDLE handle, double atime, double mtime) { - FILETIME filetime_a, filetime_m; + FILETIME filetime_as, *filetime_a = &filetime_as; + FILETIME filetime_ms, *filetime_m = &filetime_ms; + FILETIME now; - TIME_T_TO_FILETIME(atime, &filetime_a); - TIME_T_TO_FILETIME(mtime, &filetime_m); + if (uv__isinf(atime) || uv__isinf(mtime)) + GetSystemTimeAsFileTime(&now); - if (!SetFileTime(handle, NULL, &filetime_a, &filetime_m)) { + if (uv__isinf(atime)) + filetime_a = &now; + else if (uv__isnan(atime)) + filetime_a = NULL; + else + TIME_T_TO_FILETIME(atime, filetime_a); + + if (uv__isinf(mtime)) + filetime_m = &now; + else if (uv__isnan(mtime)) + filetime_m = NULL; + else + TIME_T_TO_FILETIME(mtime, filetime_m); + + if (!SetFileTime(handle, NULL, filetime_a, filetime_m)) return -1; - } return 0; } diff --git a/deps/uv/src/win/pipe.c b/deps/uv/src/win/pipe.c index d46ecb9fc702e6..d05bfd28aec8b9 100644 --- a/deps/uv/src/win/pipe.c +++ b/deps/uv/src/win/pipe.c @@ -1161,9 +1161,9 @@ int uv__pipe_accept(uv_pipe_t* server, uv_stream_t* client) { err = uv__tcp_xfer_import( (uv_tcp_t*) client, item->xfer_type, &item->xfer_info); - + uv__free(item); - + if (err != 0) return err; @@ -1738,7 +1738,7 @@ static DWORD uv__pipe_get_ipc_remote_pid(uv_pipe_t* handle) { GetNamedPipeServerProcessId(handle->handle, pid); } } - + return *pid; } @@ -2602,6 +2602,9 @@ int uv_pipe_pending_count(uv_pipe_t* handle) { int uv_pipe_getsockname(const uv_pipe_t* handle, char* buffer, size_t* size) { + if (buffer == NULL || size == NULL || *size == 0) + return UV_EINVAL; + if (handle->flags & UV_HANDLE_BOUND) return uv__pipe_getname(handle, buffer, size); @@ -2616,6 +2619,9 @@ int uv_pipe_getsockname(const uv_pipe_t* handle, char* buffer, size_t* size) { int uv_pipe_getpeername(const uv_pipe_t* handle, char* buffer, size_t* size) { + if (buffer == NULL || size == NULL || *size == 0) + return UV_EINVAL; + /* emulate unix behaviour */ if (handle->flags & UV_HANDLE_BOUND) return UV_ENOTCONN; diff --git a/deps/uv/src/win/process.c b/deps/uv/src/win/process.c index 9d48ddc6f84d6f..27605ca36f4434 100644 --- a/deps/uv/src/win/process.c +++ b/deps/uv/src/win/process.c @@ -898,7 +898,7 @@ int uv_spawn(uv_loop_t* loop, *env = NULL, *cwd = NULL; STARTUPINFOW startup; PROCESS_INFORMATION info; - DWORD process_flags; + DWORD process_flags, cwd_len; BYTE* child_stdio_buffer; uv__process_init(loop, process); @@ -947,9 +947,10 @@ int uv_spawn(uv_loop_t* loop, if (err) goto done_uv; + cwd_len = wcslen(cwd); } else { /* Inherit cwd */ - DWORD cwd_len, r; + DWORD r; cwd_len = GetCurrentDirectoryW(0, NULL); if (!cwd_len) { @@ -970,6 +971,15 @@ int uv_spawn(uv_loop_t* loop, } } + /* If cwd is too long, shorten it */ + if (cwd_len >= MAX_PATH) { + cwd_len = GetShortPathNameW(cwd, cwd, cwd_len); + if (cwd_len == 0) { + err = GetLastError(); + goto done; + } + } + /* Get PATH environment variable. */ path = find_path(env); if (path == NULL) { diff --git a/deps/uv/src/win/thread.c b/deps/uv/src/win/thread.c index bf39b88633b0d8..753cb6a34a5b9a 100644 --- a/deps/uv/src/win/thread.c +++ b/deps/uv/src/win/thread.c @@ -57,6 +57,9 @@ STATIC_ASSERT(sizeof(uv_thread_t) <= sizeof(void*)); static uv_key_t uv__current_thread_key; static uv_once_t uv__current_thread_init_guard = UV_ONCE_INIT; +static uv_once_t uv__thread_name_once = UV_ONCE_INIT; +HRESULT (WINAPI *pGetThreadDescription)(HANDLE, PWSTR*); +HRESULT (WINAPI *pSetThreadDescription)(HANDLE, PCWSTR); static void uv__init_current_thread_key(void) { @@ -95,6 +98,15 @@ int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) { return uv_thread_create_ex(tid, ¶ms, entry, arg); } + +int uv_thread_detach(uv_thread_t *tid) { + if (CloseHandle(*tid) == 0) + return uv_translate_sys_error(GetLastError()); + + return 0; +} + + int uv_thread_create_ex(uv_thread_t* tid, const uv_thread_options_t* params, void (*entry)(void *arg), @@ -269,6 +281,92 @@ int uv_thread_equal(const uv_thread_t* t1, const uv_thread_t* t2) { } +static void uv__thread_name_init_once(void) { + HMODULE m; + + m = GetModuleHandleA("api-ms-win-core-processthreads-l1-1-3.dll"); + if (m != NULL) { + pGetThreadDescription = (void*) GetProcAddress(m, "GetThreadDescription"); + pSetThreadDescription = (void*) GetProcAddress(m, "SetThreadDescription"); + } +} + + +int uv_thread_setname(const char* name) { + HRESULT hr; + WCHAR* namew; + int err; + char namebuf[UV_PTHREAD_MAX_NAMELEN_NP]; + + uv_once(&uv__thread_name_once, uv__thread_name_init_once); + + if (pSetThreadDescription == NULL) + return UV_ENOSYS; + + if (name == NULL) + return UV_EINVAL; + + strncpy(namebuf, name, sizeof(namebuf) - 1); + namebuf[sizeof(namebuf) - 1] = '\0'; + + namew = NULL; + err = uv__convert_utf8_to_utf16(namebuf, &namew); + if (err) + return err; + + hr = pSetThreadDescription(GetCurrentThread(), namew); + uv__free(namew); + if (FAILED(hr)) + return uv_translate_sys_error(HRESULT_CODE(hr)); + + return 0; +} + + +int uv_thread_getname(uv_thread_t* tid, char* name, size_t size) { + HRESULT hr; + WCHAR* namew; + char* thread_name; + size_t buf_size; + int r; + DWORD exit_code; + + uv_once(&uv__thread_name_once, uv__thread_name_init_once); + + if (pGetThreadDescription == NULL) + return UV_ENOSYS; + + if (name == NULL || size == 0) + return UV_EINVAL; + + if (tid == NULL || *tid == NULL) + return UV_EINVAL; + + /* Check if the thread handle is valid */ + if (!GetExitCodeThread(*tid, &exit_code) || exit_code != STILL_ACTIVE) + return UV_ENOENT; + + namew = NULL; + thread_name = NULL; + hr = pGetThreadDescription(*tid, &namew); + if (FAILED(hr)) + return uv_translate_sys_error(HRESULT_CODE(hr)); + + buf_size = size; + r = uv__copy_utf16_to_utf8(namew, -1, name, &buf_size); + if (r == UV_ENOBUFS) { + r = uv__convert_utf16_to_utf8(namew, wcslen(namew), &thread_name); + if (r == 0) { + uv__strscpy(name, thread_name, size); + uv__free(thread_name); + } + } + + LocalFree(namew); + return r; +} + + int uv_mutex_init(uv_mutex_t* mutex) { InitializeCriticalSection(mutex); return 0; diff --git a/deps/uv/src/win/tty.c b/deps/uv/src/win/tty.c index c0339ded2e4b76..66ca99cda83ab1 100644 --- a/deps/uv/src/win/tty.c +++ b/deps/uv/src/win/tty.c @@ -58,6 +58,9 @@ #ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING #define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004 #endif +#ifndef ENABLE_VIRTUAL_TERMINAL_INPUT +#define ENABLE_VIRTUAL_TERMINAL_INPUT 0x0200 +#endif #define CURSOR_SIZE_SMALL 25 #define CURSOR_SIZE_LARGE 100 @@ -119,7 +122,10 @@ static int uv_tty_virtual_width = -1; * handle signalling SIGWINCH */ -static HANDLE uv__tty_console_handle = INVALID_HANDLE_VALUE; +static HANDLE uv__tty_console_handle_out = INVALID_HANDLE_VALUE; +static HANDLE uv__tty_console_handle_in = INVALID_HANDLE_VALUE; +static DWORD uv__tty_console_in_original_mode = (DWORD)-1; +static volatile LONG uv__tty_console_in_need_mode_reset = 0; static int uv__tty_console_height = -1; static int uv__tty_console_width = -1; static HANDLE uv__tty_console_resized = INVALID_HANDLE_VALUE; @@ -159,19 +165,21 @@ static uv_tty_vtermstate_t uv__vterm_state = UV_TTY_UNSUPPORTED; static void uv__determine_vterm_state(HANDLE handle); void uv__console_init(void) { + DWORD dwMode; + if (uv_sem_init(&uv_tty_output_lock, 1)) abort(); - uv__tty_console_handle = CreateFileW(L"CONOUT$", - GENERIC_READ | GENERIC_WRITE, - FILE_SHARE_WRITE, - 0, - OPEN_EXISTING, - 0, - 0); - if (uv__tty_console_handle != INVALID_HANDLE_VALUE) { + uv__tty_console_handle_out = CreateFileW(L"CONOUT$", + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_WRITE, + 0, + OPEN_EXISTING, + 0, + 0); + if (uv__tty_console_handle_out != INVALID_HANDLE_VALUE) { CONSOLE_SCREEN_BUFFER_INFO sb_info; uv_mutex_init(&uv__tty_console_resize_mutex); - if (GetConsoleScreenBufferInfo(uv__tty_console_handle, &sb_info)) { + if (GetConsoleScreenBufferInfo(uv__tty_console_handle_out, &sb_info)) { uv__tty_console_width = sb_info.dwSize.X; uv__tty_console_height = sb_info.srWindow.Bottom - sb_info.srWindow.Top + 1; } @@ -179,6 +187,18 @@ void uv__console_init(void) { NULL, WT_EXECUTELONGFUNCTION); } + uv__tty_console_handle_in = CreateFileW(L"CONIN$", + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ, + 0, + OPEN_EXISTING, + 0, + 0); + if (uv__tty_console_handle_in != INVALID_HANDLE_VALUE) { + if (GetConsoleMode(uv__tty_console_handle_in, &dwMode)) { + uv__tty_console_in_original_mode = dwMode; + } + } } @@ -253,7 +273,9 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, uv_file fd, int unused) { /* Initialize TTY input specific fields. */ tty->flags |= UV_HANDLE_TTY_READABLE | UV_HANDLE_READABLE; /* TODO: remove me in v2.x. */ - tty->tty.rd.unused_ = NULL; + tty->tty.rd.mode.unused_ = NULL; + /* Partially overwrites unused_ again. */ + tty->tty.rd.mode.mode = 0; tty->tty.rd.read_line_buffer = uv_null_buf_; tty->tty.rd.read_raw_wait = NULL; @@ -344,6 +366,7 @@ static void uv__tty_capture_initial_style( int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) { DWORD flags; + DWORD try_set_flags; unsigned char was_reading; uv_alloc_cb alloc_cb; uv_read_cb read_cb; @@ -353,14 +376,19 @@ int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) { return UV_EINVAL; } - if (!!mode == !!(tty->flags & UV_HANDLE_TTY_RAW)) { + if ((int)mode == tty->tty.rd.mode.mode) { return 0; } + try_set_flags = 0; switch (mode) { case UV_TTY_MODE_NORMAL: flags = ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT; break; + case UV_TTY_MODE_RAW_VT: + try_set_flags = ENABLE_VIRTUAL_TERMINAL_INPUT; + InterlockedExchange(&uv__tty_console_in_need_mode_reset, 1); + /* fallthrough */ case UV_TTY_MODE_RAW: flags = ENABLE_WINDOW_INPUT; break; @@ -386,16 +414,16 @@ int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) { } uv_sem_wait(&uv_tty_output_lock); - if (!SetConsoleMode(tty->handle, flags)) { + if (!SetConsoleMode(tty->handle, flags | try_set_flags) && + !SetConsoleMode(tty->handle, flags)) { err = uv_translate_sys_error(GetLastError()); uv_sem_post(&uv_tty_output_lock); return err; } uv_sem_post(&uv_tty_output_lock); - /* Update flag. */ - tty->flags &= ~UV_HANDLE_TTY_RAW; - tty->flags |= mode ? UV_HANDLE_TTY_RAW : 0; + /* Update mode. */ + tty->tty.rd.mode.mode = mode; /* If we just stopped reading, restart. */ if (was_reading) { @@ -614,7 +642,7 @@ static void uv__tty_queue_read_line(uv_loop_t* loop, uv_tty_t* handle) { static void uv__tty_queue_read(uv_loop_t* loop, uv_tty_t* handle) { - if (handle->flags & UV_HANDLE_TTY_RAW) { + if (uv__is_raw_tty_mode(handle->tty.rd.mode.mode)) { uv__tty_queue_read_raw(loop, handle); } else { uv__tty_queue_read_line(loop, handle); @@ -702,7 +730,7 @@ void uv_process_tty_read_raw_req(uv_loop_t* loop, uv_tty_t* handle, handle->flags &= ~UV_HANDLE_READ_PENDING; if (!(handle->flags & UV_HANDLE_READING) || - !(handle->flags & UV_HANDLE_TTY_RAW)) { + !(uv__is_raw_tty_mode(handle->tty.rd.mode.mode))) { goto out; } @@ -1050,7 +1078,7 @@ int uv__tty_read_stop(uv_tty_t* handle) { if (!(handle->flags & UV_HANDLE_READ_PENDING)) return 0; - if (handle->flags & UV_HANDLE_TTY_RAW) { + if (uv__is_raw_tty_mode(handle->tty.rd.mode.mode)) { /* Cancel raw read. Write some bullshit event to force the console wait to * return. */ memset(&record, 0, sizeof record); @@ -2293,7 +2321,17 @@ void uv__tty_endgame(uv_loop_t* loop, uv_tty_t* handle) { int uv_tty_reset_mode(void) { - /* Not necessary to do anything. */ + /** + * Shells on Windows do know to reset output flags after a program exits, + * but not necessarily input flags, so we do that for them. + */ + if ( + uv__tty_console_handle_in != INVALID_HANDLE_VALUE && + uv__tty_console_in_original_mode != (DWORD)-1 && + InterlockedExchange(&uv__tty_console_in_need_mode_reset, 0) != 0 + ) { + SetConsoleMode(uv__tty_console_handle_in, uv__tty_console_in_original_mode); + } return 0; } @@ -2390,7 +2428,7 @@ static void uv__tty_console_signal_resize(void) { CONSOLE_SCREEN_BUFFER_INFO sb_info; int width, height; - if (!GetConsoleScreenBufferInfo(uv__tty_console_handle, &sb_info)) + if (!GetConsoleScreenBufferInfo(uv__tty_console_handle_out, &sb_info)) return; width = sb_info.dwSize.X; diff --git a/deps/uv/src/win/udp.c b/deps/uv/src/win/udp.c index 5c8f6e1dd0b449..e0873c2a899c24 100644 --- a/deps/uv/src/win/udp.c +++ b/deps/uv/src/win/udp.c @@ -1101,7 +1101,8 @@ int uv__udp_try_send(uv_udp_t* handle, struct sockaddr_storage converted; int err; - assert(nbufs > 0); + if (nbufs < 1) + return UV_EINVAL; if (addr != NULL) { err = uv__convert_to_localhost_if_unspecified(addr, &converted); @@ -1141,3 +1142,21 @@ int uv__udp_try_send(uv_udp_t* handle, return bytes; } + + +int uv__udp_try_send2(uv_udp_t* handle, + unsigned int count, + uv_buf_t* bufs[/*count*/], + unsigned int nbufs[/*count*/], + struct sockaddr* addrs[/*count*/]) { + unsigned int i; + int r; + + for (i = 0; i < count; i++) { + r = uv_udp_try_send(handle, bufs[i], nbufs[i], addrs[i]); + if (r < 0) + return i > 0 ? i : r; /* Error if first packet, else send count. */ + } + + return i; +} diff --git a/deps/uv/src/win/util.c b/deps/uv/src/win/util.c index e0dba1aaa94e28..57061bf8d703fe 100644 --- a/deps/uv/src/win/util.c +++ b/deps/uv/src/win/util.c @@ -191,7 +191,7 @@ int uv_cwd(char* buffer, size_t* size) { WCHAR *utf16_buffer; int r; - if (buffer == NULL || size == NULL) { + if (buffer == NULL || size == NULL || *size == 0) { return UV_EINVAL; } @@ -874,56 +874,100 @@ void uv_free_interface_addresses(uv_interface_address_t* addresses, int uv_getrusage(uv_rusage_t *uv_rusage) { - FILETIME createTime, exitTime, kernelTime, userTime; - SYSTEMTIME kernelSystemTime, userSystemTime; - PROCESS_MEMORY_COUNTERS memCounters; - IO_COUNTERS ioCounters; + FILETIME create_time, exit_time, kernel_time, user_time; + SYSTEMTIME kernel_system_time, user_system_time; + PROCESS_MEMORY_COUNTERS mem_counters; + IO_COUNTERS io_counters; int ret; - ret = GetProcessTimes(GetCurrentProcess(), &createTime, &exitTime, &kernelTime, &userTime); + ret = GetProcessTimes(GetCurrentProcess(), + &create_time, + &exit_time, + &kernel_time, + &user_time); if (ret == 0) { return uv_translate_sys_error(GetLastError()); } - ret = FileTimeToSystemTime(&kernelTime, &kernelSystemTime); + ret = FileTimeToSystemTime(&kernel_time, &kernel_system_time); if (ret == 0) { return uv_translate_sys_error(GetLastError()); } - ret = FileTimeToSystemTime(&userTime, &userSystemTime); + ret = FileTimeToSystemTime(&user_time, &user_system_time); if (ret == 0) { return uv_translate_sys_error(GetLastError()); } ret = GetProcessMemoryInfo(GetCurrentProcess(), - &memCounters, - sizeof(memCounters)); + &mem_counters, + sizeof(mem_counters)); if (ret == 0) { return uv_translate_sys_error(GetLastError()); } - ret = GetProcessIoCounters(GetCurrentProcess(), &ioCounters); + ret = GetProcessIoCounters(GetCurrentProcess(), &io_counters); if (ret == 0) { return uv_translate_sys_error(GetLastError()); } memset(uv_rusage, 0, sizeof(*uv_rusage)); - uv_rusage->ru_utime.tv_sec = userSystemTime.wHour * 3600 + - userSystemTime.wMinute * 60 + - userSystemTime.wSecond; - uv_rusage->ru_utime.tv_usec = userSystemTime.wMilliseconds * 1000; + uv_rusage->ru_utime.tv_sec = user_system_time.wHour * 3600 + + user_system_time.wMinute * 60 + + user_system_time.wSecond; + uv_rusage->ru_utime.tv_usec = user_system_time.wMilliseconds * 1000; - uv_rusage->ru_stime.tv_sec = kernelSystemTime.wHour * 3600 + - kernelSystemTime.wMinute * 60 + - kernelSystemTime.wSecond; - uv_rusage->ru_stime.tv_usec = kernelSystemTime.wMilliseconds * 1000; + uv_rusage->ru_stime.tv_sec = kernel_system_time.wHour * 3600 + + kernel_system_time.wMinute * 60 + + kernel_system_time.wSecond; + uv_rusage->ru_stime.tv_usec = kernel_system_time.wMilliseconds * 1000; - uv_rusage->ru_majflt = (uint64_t) memCounters.PageFaultCount; - uv_rusage->ru_maxrss = (uint64_t) memCounters.PeakWorkingSetSize / 1024; + uv_rusage->ru_majflt = (uint64_t) mem_counters.PageFaultCount; + uv_rusage->ru_maxrss = (uint64_t) mem_counters.PeakWorkingSetSize / 1024; - uv_rusage->ru_oublock = (uint64_t) ioCounters.WriteOperationCount; - uv_rusage->ru_inblock = (uint64_t) ioCounters.ReadOperationCount; + uv_rusage->ru_oublock = (uint64_t) io_counters.WriteOperationCount; + uv_rusage->ru_inblock = (uint64_t) io_counters.ReadOperationCount; + + return 0; +} + + +int uv_getrusage_thread(uv_rusage_t* uv_rusage) { + FILETIME create_time, exit_time, kernel_time, user_time; + SYSTEMTIME kernel_system_time, user_system_time; + int ret; + + ret = GetThreadTimes(GetCurrentThread(), + &create_time, + &exit_time, + &kernel_time, + &user_time); + if (ret == 0) { + return uv_translate_sys_error(GetLastError()); + } + + ret = FileTimeToSystemTime(&kernel_time, &kernel_system_time); + if (ret == 0) { + return uv_translate_sys_error(GetLastError()); + } + + ret = FileTimeToSystemTime(&user_time, &user_system_time); + if (ret == 0) { + return uv_translate_sys_error(GetLastError()); + } + + memset(uv_rusage, 0, sizeof(*uv_rusage)); + + uv_rusage->ru_utime.tv_sec = user_system_time.wHour * 3600 + + user_system_time.wMinute * 60 + + user_system_time.wSecond; + uv_rusage->ru_utime.tv_usec = user_system_time.wMilliseconds * 1000; + + uv_rusage->ru_stime.tv_sec = kernel_system_time.wHour * 3600 + + kernel_system_time.wMinute * 60 + + kernel_system_time.wSecond; + uv_rusage->ru_stime.tv_usec = kernel_system_time.wMilliseconds * 1000; return 0; } @@ -972,6 +1016,7 @@ int uv_os_homedir(char* buffer, size_t* size) { int uv_os_tmpdir(char* buffer, size_t* size) { + int r; wchar_t *path; size_t len; @@ -1010,7 +1055,9 @@ int uv_os_tmpdir(char* buffer, size_t* size) { path[len] = L'\0'; } - return uv__copy_utf16_to_utf8(path, len, buffer, size); + r = uv__copy_utf16_to_utf8(path, len, buffer, size); + uv__free(path); + return r; } @@ -1589,7 +1636,7 @@ int uv_os_uname(uv_utsname_t* buffer) { version_size = sizeof(buffer->version) - version_size; r = uv__copy_utf16_to_utf8(os_info.szCSDVersion, -1, - buffer->version + + buffer->version + sizeof(buffer->version) - version_size, &version_size); if (r) diff --git a/deps/uv/src/win/winapi.c b/deps/uv/src/win/winapi.c index a74108db03e701..315a0d49aff50b 100644 --- a/deps/uv/src/win/winapi.c +++ b/deps/uv/src/win/winapi.c @@ -36,9 +36,6 @@ sNtQueryDirectoryFile pNtQueryDirectoryFile; sNtQuerySystemInformation pNtQuerySystemInformation; sNtQueryInformationProcess pNtQueryInformationProcess; -/* Kernel32 function pointers */ -sGetQueuedCompletionStatusEx pGetQueuedCompletionStatusEx; - /* Powrprof.dll function pointer */ sPowerRegisterSuspendResumeNotification pPowerRegisterSuspendResumeNotification; @@ -55,7 +52,6 @@ void uv__winapi_init(void) { HMODULE ntdll_module; HMODULE powrprof_module; HMODULE user32_module; - HMODULE kernel32_module; HMODULE ws2_32_module; HMODULE api_win_core_file_module; @@ -121,15 +117,6 @@ void uv__winapi_init(void) { uv_fatal_error(GetLastError(), "GetProcAddress"); } - kernel32_module = GetModuleHandleA("kernel32.dll"); - if (kernel32_module == NULL) { - uv_fatal_error(GetLastError(), "GetModuleHandleA"); - } - - pGetQueuedCompletionStatusEx = (sGetQueuedCompletionStatusEx) GetProcAddress( - kernel32_module, - "GetQueuedCompletionStatusEx"); - powrprof_module = LoadLibraryExA("powrprof.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32); if (powrprof_module != NULL) { pPowerRegisterSuspendResumeNotification = (sPowerRegisterSuspendResumeNotification) diff --git a/deps/uv/src/win/winapi.h b/deps/uv/src/win/winapi.h index 5800e70dfd7d11..b9c9f1abc8899e 100644 --- a/deps/uv/src/win/winapi.h +++ b/deps/uv/src/win/winapi.h @@ -4145,45 +4145,40 @@ typedef struct _FILE_STAT_BASIC_INFORMATION { ULONG DeviceType; ULONG DeviceCharacteristics; ULONG Reserved; - FILE_ID_128 FileId128; LARGE_INTEGER VolumeSerialNumber; + FILE_ID_128 FileId128; } FILE_STAT_BASIC_INFORMATION; #endif -/* MinGW already has a definition for REPARSE_DATA_BUFFER, but mingw-w64 does - * not. - */ -#if defined(_MSC_VER) || defined(__MINGW64_VERSION_MAJOR) - typedef struct _REPARSE_DATA_BUFFER { - ULONG ReparseTag; - USHORT ReparseDataLength; - USHORT Reserved; - union { - struct { - USHORT SubstituteNameOffset; - USHORT SubstituteNameLength; - USHORT PrintNameOffset; - USHORT PrintNameLength; - ULONG Flags; - WCHAR PathBuffer[1]; - } SymbolicLinkReparseBuffer; - struct { - USHORT SubstituteNameOffset; - USHORT SubstituteNameLength; - USHORT PrintNameOffset; - USHORT PrintNameLength; - WCHAR PathBuffer[1]; - } MountPointReparseBuffer; - struct { - UCHAR DataBuffer[1]; - } GenericReparseBuffer; - struct { - ULONG StringCount; - WCHAR StringList[1]; - } AppExecLinkReparseBuffer; - }; - } REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER; -#endif +typedef struct _REPARSE_DATA_BUFFER { + ULONG ReparseTag; + USHORT ReparseDataLength; + USHORT Reserved; + union { + struct { + USHORT SubstituteNameOffset; + USHORT SubstituteNameLength; + USHORT PrintNameOffset; + USHORT PrintNameLength; + ULONG Flags; + WCHAR PathBuffer[1]; + } SymbolicLinkReparseBuffer; + struct { + USHORT SubstituteNameOffset; + USHORT SubstituteNameLength; + USHORT PrintNameOffset; + USHORT PrintNameLength; + WCHAR PathBuffer[1]; + } MountPointReparseBuffer; + struct { + UCHAR DataBuffer[1]; + } GenericReparseBuffer; + struct { + ULONG StringCount; + WCHAR StringList[1]; + } AppExecLinkReparseBuffer; + }; +} REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER; typedef struct _IO_STATUS_BLOCK { union { @@ -4292,6 +4287,22 @@ typedef struct _FILE_BOTH_DIR_INFORMATION { WCHAR FileName[1]; } FILE_BOTH_DIR_INFORMATION, *PFILE_BOTH_DIR_INFORMATION; +typedef struct _FILE_ID_FULL_DIR_INFORMATION { + ULONG NextEntryOffset; + ULONG FileIndex; + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER EndOfFile; + LARGE_INTEGER AllocationSize; + ULONG FileAttributes; + ULONG FileNameLength; + ULONG EaSize; + LARGE_INTEGER FileId; + WCHAR FileName[1]; +} FILE_ID_FULL_DIR_INFORMATION, *PFILE_ID_FULL_DIR_INFORMATION; + typedef struct _FILE_BASIC_INFORMATION { LARGE_INTEGER CreationTime; LARGE_INTEGER LastAccessTime; @@ -4661,15 +4672,6 @@ typedef NTSTATUS (NTAPI *sNtQueryInformationProcess) # define SYMBOLIC_LINK_FLAG_DIRECTORY 0x1 #endif -#if defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR) - typedef struct _OVERLAPPED_ENTRY { - ULONG_PTR lpCompletionKey; - LPOVERLAPPED lpOverlapped; - ULONG_PTR Internal; - DWORD dwNumberOfBytesTransferred; - } OVERLAPPED_ENTRY, *LPOVERLAPPED_ENTRY; -#endif - /* from wincon.h */ #ifndef ENABLE_INSERT_MODE # define ENABLE_INSERT_MODE 0x20 @@ -4716,14 +4718,6 @@ typedef NTSTATUS (NTAPI *sNtQueryInformationProcess) # define ERROR_MUI_FILE_NOT_LOADED 15105 #endif -typedef BOOL (WINAPI *sGetQueuedCompletionStatusEx) - (HANDLE CompletionPort, - LPOVERLAPPED_ENTRY lpCompletionPortEntries, - ULONG ulCount, - PULONG ulNumEntriesRemoved, - DWORD dwMilliseconds, - BOOL fAlertable); - /* from powerbase.h */ #ifndef DEVICE_NOTIFY_CALLBACK # define DEVICE_NOTIFY_CALLBACK 2 @@ -4818,9 +4812,6 @@ extern sNtQueryDirectoryFile pNtQueryDirectoryFile; extern sNtQuerySystemInformation pNtQuerySystemInformation; extern sNtQueryInformationProcess pNtQueryInformationProcess; -/* Kernel32 function pointers */ -extern sGetQueuedCompletionStatusEx pGetQueuedCompletionStatusEx; - /* Powrprof.dll function pointer */ extern sPowerRegisterSuspendResumeNotification pPowerRegisterSuspendResumeNotification; diff --git a/deps/uv/src/win/winsock.h b/deps/uv/src/win/winsock.h index 2af958870a7de6..bb3808a35c27e6 100644 --- a/deps/uv/src/win/winsock.h +++ b/deps/uv/src/win/winsock.h @@ -154,47 +154,6 @@ typedef struct _AFD_RECV_INFO { #define IOCTL_AFD_POLL \ _AFD_CONTROL_CODE(AFD_POLL, METHOD_BUFFERED) -#if defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR) -typedef struct _IP_ADAPTER_UNICAST_ADDRESS_XP { - /* FIXME: __C89_NAMELESS was removed */ - /* __C89_NAMELESS */ union { - ULONGLONG Alignment; - /* __C89_NAMELESS */ struct { - ULONG Length; - DWORD Flags; - }; - }; - struct _IP_ADAPTER_UNICAST_ADDRESS_XP *Next; - SOCKET_ADDRESS Address; - IP_PREFIX_ORIGIN PrefixOrigin; - IP_SUFFIX_ORIGIN SuffixOrigin; - IP_DAD_STATE DadState; - ULONG ValidLifetime; - ULONG PreferredLifetime; - ULONG LeaseLifetime; -} IP_ADAPTER_UNICAST_ADDRESS_XP,*PIP_ADAPTER_UNICAST_ADDRESS_XP; - -typedef struct _IP_ADAPTER_UNICAST_ADDRESS_LH { - union { - ULONGLONG Alignment; - struct { - ULONG Length; - DWORD Flags; - }; - }; - struct _IP_ADAPTER_UNICAST_ADDRESS_LH *Next; - SOCKET_ADDRESS Address; - IP_PREFIX_ORIGIN PrefixOrigin; - IP_SUFFIX_ORIGIN SuffixOrigin; - IP_DAD_STATE DadState; - ULONG ValidLifetime; - ULONG PreferredLifetime; - ULONG LeaseLifetime; - UINT8 OnLinkPrefixLength; -} IP_ADAPTER_UNICAST_ADDRESS_LH,*PIP_ADAPTER_UNICAST_ADDRESS_LH; - -#endif - int uv__convert_to_localhost_if_unspecified(const struct sockaddr* addr, struct sockaddr_storage* storage); diff --git a/deps/uv/test/runner-unix.c b/deps/uv/test/runner-unix.c index 81560add82043e..3d14cb69b29ee1 100644 --- a/deps/uv/test/runner-unix.c +++ b/deps/uv/test/runner-unix.c @@ -367,6 +367,7 @@ long int process_output_size(process_info_t *p) { /* Copy the contents of the stdio output buffer to `fd`. */ int process_copy_output(process_info_t* p, FILE* stream) { char buf[1024]; + int partial; int r; r = fseek(p->stdout_file, 0, SEEK_SET); @@ -375,9 +376,9 @@ int process_copy_output(process_info_t* p, FILE* stream) { return -1; } - /* TODO: what if the line is longer than buf */ + partial = 0; while ((r = fread(buf, 1, sizeof(buf), p->stdout_file)) != 0) - print_lines(buf, r, stream); + partial = print_lines(buf, r, stream, partial); if (ferror(p->stdout_file)) { perror("read"); diff --git a/deps/uv/test/runner-win.c b/deps/uv/test/runner-win.c index 6c6e35f7731327..8035ca62f8ec9f 100644 --- a/deps/uv/test/runner-win.c +++ b/deps/uv/test/runner-win.c @@ -219,6 +219,7 @@ long int process_output_size(process_info_t *p) { int process_copy_output(process_info_t* p, FILE* stream) { char buf[1024]; + int partial; int fd, r; fd = _open_osfhandle((intptr_t)p->stdio_out, _O_RDONLY | _O_TEXT); @@ -229,8 +230,9 @@ int process_copy_output(process_info_t* p, FILE* stream) { if (r < 0) return -1; + partial = 0; while ((r = _read(fd, buf, sizeof(buf))) != 0) - print_lines(buf, r, stream); + partial = print_lines(buf, r, stream, partial); _close(fd); return 0; diff --git a/deps/uv/test/runner.c b/deps/uv/test/runner.c index d1dd02f5ce0806..87e7db0b05c5ea 100644 --- a/deps/uv/test/runner.c +++ b/deps/uv/test/runner.c @@ -27,6 +27,11 @@ #include "task.h" #include "uv.h" +/* Refs: https://github.com/libuv/libuv/issues/4369 */ +#if defined(__ANDROID__) +#include +#endif + char executable_path[sizeof(executable_path)]; @@ -142,6 +147,13 @@ void log_tap_result(int test_count, fflush(stdout); } +void enable_fdsan(void) { +/* Refs: https://github.com/libuv/libuv/issues/4369 */ +#if defined(__ANDROID__) + android_fdsan_set_error_level(ANDROID_FDSAN_ERROR_LEVEL_WARN_ALWAYS); +#endif +} + int run_test(const char* test, int benchmark_output, @@ -160,6 +172,8 @@ int run_test(const char* test, main_proc = NULL; process_count = 0; + enable_fdsan(); + #ifndef _WIN32 /* Clean up stale socket from previous run. */ remove(TEST_PIPENAME); @@ -412,13 +426,17 @@ void print_tests(FILE* stream) { } -void print_lines(const char* buffer, size_t size, FILE* stream) { +int print_lines(const char* buffer, size_t size, FILE* stream, int partial) { const char* start; const char* end; start = buffer; while ((end = memchr(start, '\n', &buffer[size] - start))) { - fputs("# ", stream); + if (partial == 0) + fputs("# ", stream); + else + partial = 0; + fwrite(start, 1, (int)(end - start), stream); fputs("\n", stream); fflush(stream); @@ -427,9 +445,13 @@ void print_lines(const char* buffer, size_t size, FILE* stream) { end = &buffer[size]; if (start < end) { - fputs("# ", stream); + if (partial == 0) + fputs("# ", stream); + fwrite(start, 1, (int)(end - start), stream); - fputs("\n", stream); fflush(stream); + return 1; } + + return 0; } diff --git a/deps/uv/test/runner.h b/deps/uv/test/runner.h index 6801564f961c31..ff7d4eec9b6870 100644 --- a/deps/uv/test/runner.h +++ b/deps/uv/test/runner.h @@ -123,7 +123,7 @@ int run_test_part(const char* test, const char* part); void print_tests(FILE* stream); /* Print lines in |buffer| as TAP diagnostics to |stream|. */ -void print_lines(const char* buffer, size_t size, FILE* stream); +int print_lines(const char* buffer, size_t size, FILE* stream, int partial); /* * Stuff that should be implemented by test-runner-.h diff --git a/deps/uv/test/test-connect-unspecified.c b/deps/uv/test/test-connect-unspecified.c index 73e59a9972b670..ebed8c3c20b809 100644 --- a/deps/uv/test/test-connect-unspecified.c +++ b/deps/uv/test/test-connect-unspecified.c @@ -22,11 +22,7 @@ #include "uv.h" #include "task.h" -static void connect_4(uv_connect_t* req, int status) { - ASSERT_NE(status, UV_EADDRNOTAVAIL); -} - -static void connect_6(uv_connect_t* req, int status) { +static void connect_cb(uv_connect_t* req, int status) { ASSERT_NE(status, UV_EADDRNOTAVAIL); } @@ -46,7 +42,7 @@ TEST_IMPL(connect_unspecified) { ASSERT_OK(uv_tcp_connect(&connect4, &socket4, (const struct sockaddr*) &addr4, - connect_4)); + connect_cb)); if (can_ipv6()) { ASSERT_OK(uv_tcp_init(loop, &socket6)); @@ -54,7 +50,7 @@ TEST_IMPL(connect_unspecified) { ASSERT_OK(uv_tcp_connect(&connect6, &socket6, (const struct sockaddr*) &addr6, - connect_6)); + connect_cb)); } ASSERT_OK(uv_run(loop, UV_RUN_DEFAULT)); diff --git a/deps/uv/test/test-fs-event.c b/deps/uv/test/test-fs-event.c index bb223a5f654c03..f224181fc36855 100644 --- a/deps/uv/test/test-fs-event.c +++ b/deps/uv/test/test-fs-event.c @@ -32,7 +32,7 @@ static uv_fs_event_t fs_event; static const char file_prefix[] = "fsevent-"; static const int fs_event_file_count = 16; -#if defined(__APPLE__) || defined(_WIN32) +#if (defined(__APPLE__) && !defined(__TSAN__)) || defined(_WIN32) static const char file_prefix_in_subdir[] = "subdir"; static int fs_multievent_cb_called; #endif @@ -153,7 +153,14 @@ static void fs_event_cb_del_dir(uv_fs_event_t* handle, ASSERT_PTR_EQ(handle, &fs_event); ASSERT_OK(status); ASSERT(events == UV_CHANGE || events == UV_RENAME); + /* There is a bug in the FreeBSD kernel where the filename is sometimes NULL. + * Refs: https://github.com/libuv/libuv/issues/4606 + */ + #if defined(__FreeBSD__) + ASSERT(filename == NULL || strcmp(filename, "watch_del_dir") == 0); + #else ASSERT_OK(strcmp(filename, "watch_del_dir")); + #endif ASSERT_OK(uv_fs_event_stop(handle)); uv_close((uv_handle_t*)handle, close_cb); } @@ -243,7 +250,7 @@ static void fs_event_cb_dir_multi_file(uv_fs_event_t* handle, } } -#if defined(__APPLE__) || defined(_WIN32) +#if (defined(__APPLE__) && !defined(__TSAN__)) || defined(_WIN32) static const char* fs_event_get_filename_in_subdir(int i) { snprintf(fs_event_filename, sizeof(fs_event_filename), @@ -1121,7 +1128,7 @@ TEST_IMPL(fs_event_getpath) { ASSERT_EQ(r, UV_EINVAL); r = uv_fs_event_start(&fs_event, fail_cb, watch_dir[i], 0); ASSERT_OK(r); - len = 0; + len = 1; r = uv_fs_event_getpath(&fs_event, buf, &len); ASSERT_EQ(r, UV_ENOBUFS); ASSERT_LT(len, sizeof buf); /* sanity check */ diff --git a/deps/uv/test/test-fs.c b/deps/uv/test/test-fs.c index 33cbd428707c36..4761b15bad188b 100644 --- a/deps/uv/test/test-fs.c +++ b/deps/uv/test/test-fs.c @@ -59,6 +59,18 @@ #define TOO_LONG_NAME_LENGTH 65536 #define PATHMAX 4096 +#ifdef _WIN32 +static const int is_win32 = 1; +#else +static const int is_win32 = 0; +#endif + +#if defined(__APPLE__) || defined(__SUNPRO_C) +static const int is_apple_or_sunpro_c = 1; +#else +static const int is_apple_or_sunpro_c = 0; +#endif + typedef struct { const char* path; double atime; @@ -827,43 +839,70 @@ static void check_utime(const char* path, ASSERT_OK(req.result); s = &req.statbuf; - if (s->st_atim.tv_nsec == 0 && s->st_mtim.tv_nsec == 0) { - /* - * Test sub-second timestamps only when supported (such as Windows with + if (isfinite(atime)) { + /* Test sub-second timestamps only when supported (such as Windows with * NTFS). Some other platforms support sub-second timestamps, but that * support is filesystem-dependent. Notably OS X (HFS Plus) does NOT * support sub-second timestamps. But kernels may round or truncate in * either direction, so we may accept either possible answer. */ -#ifdef _WIN32 - ASSERT_DOUBLE_EQ(atime, (long) atime); - ASSERT_DOUBLE_EQ(mtime, (long) atime); -#endif - if (atime > 0 || (long) atime == atime) - ASSERT_EQ(s->st_atim.tv_sec, (long) atime); - if (mtime > 0 || (long) mtime == mtime) - ASSERT_EQ(s->st_mtim.tv_sec, (long) mtime); - ASSERT_GE(s->st_atim.tv_sec, (long) atime - 1); - ASSERT_GE(s->st_mtim.tv_sec, (long) mtime - 1); - ASSERT_LE(s->st_atim.tv_sec, (long) atime); - ASSERT_LE(s->st_mtim.tv_sec, (long) mtime); + if (s->st_atim.tv_nsec == 0) { + if (is_win32) + ASSERT_DOUBLE_EQ(atime, (long) atime); + if (atime > 0 || (long) atime == atime) + ASSERT_EQ(s->st_atim.tv_sec, (long) atime); + ASSERT_GE(s->st_atim.tv_sec, (long) atime - 1); + ASSERT_LE(s->st_atim.tv_sec, (long) atime); + } else { + double st_atim; + /* TODO(vtjnash): would it be better to normalize this? */ + if (!is_apple_or_sunpro_c) + ASSERT_DOUBLE_GE(s->st_atim.tv_nsec, 0); + st_atim = s->st_atim.tv_sec + s->st_atim.tv_nsec / 1e9; + /* Linux does not allow reading reliably the atime of a symlink + * since readlink() can update it + */ + if (!test_lutime) + ASSERT_DOUBLE_EQ(st_atim, atime); + } + } else if (isinf(atime)) { + /* We test with timestamps that are in the distant past + * (if you're a Gen Z-er) so check it's more recent than that. + */ + ASSERT_GT(s->st_atim.tv_sec, 1739710000); } else { - double st_atim; - double st_mtim; -#if !defined(__APPLE__) && !defined(__SUNPRO_C) - /* TODO(vtjnash): would it be better to normalize this? */ - ASSERT_DOUBLE_GE(s->st_atim.tv_nsec, 0); - ASSERT_DOUBLE_GE(s->st_mtim.tv_nsec, 0); -#endif - st_atim = s->st_atim.tv_sec + s->st_atim.tv_nsec / 1e9; - st_mtim = s->st_mtim.tv_sec + s->st_mtim.tv_nsec / 1e9; - /* - * Linux does not allow reading reliably the atime of a symlink - * since readlink() can update it + ASSERT_OK(0); + } + + if (isfinite(mtime)) { + /* Test sub-second timestamps only when supported (such as Windows with + * NTFS). Some other platforms support sub-second timestamps, but that + * support is filesystem-dependent. Notably OS X (HFS Plus) does NOT + * support sub-second timestamps. But kernels may round or truncate in + * either direction, so we may accept either possible answer. */ - if (!test_lutime) - ASSERT_DOUBLE_EQ(st_atim, atime); - ASSERT_DOUBLE_EQ(st_mtim, mtime); + if (s->st_mtim.tv_nsec == 0) { + if (is_win32) + ASSERT_DOUBLE_EQ(mtime, (long) atime); + if (mtime > 0 || (long) mtime == mtime) + ASSERT_EQ(s->st_mtim.tv_sec, (long) mtime); + ASSERT_GE(s->st_mtim.tv_sec, (long) mtime - 1); + ASSERT_LE(s->st_mtim.tv_sec, (long) mtime); + } else { + double st_mtim; + /* TODO(vtjnash): would it be better to normalize this? */ + if (!is_apple_or_sunpro_c) + ASSERT_DOUBLE_GE(s->st_mtim.tv_nsec, 0); + st_mtim = s->st_mtim.tv_sec + s->st_mtim.tv_nsec / 1e9; + ASSERT_DOUBLE_EQ(st_mtim, mtime); + } + } else if (isinf(mtime)) { + /* We test with timestamps that are in the distant past + * (if you're a Gen Z-er) so check it's more recent than that. + */ + ASSERT_GT(s->st_mtim.tv_sec, 1739710000); + } else { + ASSERT_OK(0); } uv_fs_req_cleanup(&req); @@ -1607,6 +1646,50 @@ TEST_IMPL(fs_fstat) { } +TEST_IMPL(fs_fstat_st_dev) { + uv_fs_t req; + uv_fs_t req_link; + uv_loop_t* loop = uv_default_loop(); + char* test_file = "tmp_st_dev"; + char* symlink_file = "tmp_st_dev_link"; + + unlink(test_file); + unlink(symlink_file); + + // Create file + int r = uv_fs_open(NULL, &req, test_file, UV_FS_O_RDWR | UV_FS_O_CREAT, + S_IWUSR | S_IRUSR, NULL); + ASSERT_GE(r, 0); + ASSERT_GE(req.result, 0); + uv_fs_req_cleanup(&req); + + // Create a symlink + r = uv_fs_symlink(loop, &req, test_file, symlink_file, 0, NULL); + ASSERT_EQ(r, 0); + uv_fs_req_cleanup(&req); + + // Call uv_fs_fstat for file + r = uv_fs_stat(loop, &req, test_file, NULL); + ASSERT_EQ(r, 0); + + // Call uv_fs_fstat for symlink + r = uv_fs_stat(loop, &req_link, symlink_file, NULL); + ASSERT_EQ(r, 0); + + // Compare st_dev + ASSERT_EQ(((uv_stat_t*)req.ptr)->st_dev, ((uv_stat_t*)req_link.ptr)->st_dev); + + // Cleanup + uv_fs_req_cleanup(&req); + uv_fs_req_cleanup(&req_link); + unlink(test_file); + unlink(symlink_file); + + MAKE_VALGRIND_HAPPY(loop); + return 0; +} + + TEST_IMPL(fs_fstat_stdio) { int fd; int res; @@ -2684,13 +2767,46 @@ TEST_IMPL(fs_utime) { atime = mtime = 400497753.25; /* 1982-09-10 11:22:33.25 */ - r = uv_fs_utime(NULL, &req, path, atime, mtime, NULL); - ASSERT_OK(r); + ASSERT_OK(uv_fs_utime(NULL, &req, path, atime, mtime, NULL)); + ASSERT_OK(req.result); + uv_fs_req_cleanup(&req); + check_utime(path, atime, mtime, /* test_lutime */ 0); + + ASSERT_OK(uv_fs_utime(NULL, + &req, + path, + UV_FS_UTIME_OMIT, + UV_FS_UTIME_OMIT, + NULL)); + ASSERT_OK(req.result); + uv_fs_req_cleanup(&req); + check_utime(path, atime, mtime, /* test_lutime */ 0); + + ASSERT_OK(uv_fs_utime(NULL, + &req, + path, + UV_FS_UTIME_NOW, + UV_FS_UTIME_OMIT, + NULL)); ASSERT_OK(req.result); uv_fs_req_cleanup(&req); + check_utime(path, UV_FS_UTIME_NOW, mtime, /* test_lutime */ 0); + ASSERT_OK(uv_fs_utime(NULL, &req, path, atime, mtime, NULL)); + ASSERT_OK(req.result); + uv_fs_req_cleanup(&req); check_utime(path, atime, mtime, /* test_lutime */ 0); + ASSERT_OK(uv_fs_utime(NULL, + &req, + path, + UV_FS_UTIME_OMIT, + UV_FS_UTIME_NOW, + NULL)); + ASSERT_OK(req.result); + uv_fs_req_cleanup(&req); + check_utime(path, atime, UV_FS_UTIME_NOW, /* test_lutime */ 0); + atime = mtime = 1291404900.25; /* 2010-12-03 20:35:00.25 - mees <3 */ checkme.path = path; checkme.atime = atime; @@ -2824,9 +2940,43 @@ TEST_IMPL(fs_futime) { ASSERT_OK(req.result); #endif uv_fs_req_cleanup(&req); + check_utime(path, atime, mtime, /* test_lutime */ 0); + ASSERT_OK(uv_fs_futime(NULL, + &req, + file, + UV_FS_UTIME_OMIT, + UV_FS_UTIME_OMIT, + NULL)); + ASSERT_OK(req.result); + uv_fs_req_cleanup(&req); check_utime(path, atime, mtime, /* test_lutime */ 0); + ASSERT_OK(uv_fs_futime(NULL, + &req, + file, + UV_FS_UTIME_NOW, + UV_FS_UTIME_OMIT, + NULL)); + ASSERT_OK(req.result); + uv_fs_req_cleanup(&req); + check_utime(path, UV_FS_UTIME_NOW, mtime, /* test_lutime */ 0); + + ASSERT_OK(uv_fs_futime(NULL, &req, file, atime, mtime, NULL)); + ASSERT_OK(req.result); + uv_fs_req_cleanup(&req); + check_utime(path, atime, mtime, /* test_lutime */ 0); + + ASSERT_OK(uv_fs_futime(NULL, + &req, + file, + UV_FS_UTIME_OMIT, + UV_FS_UTIME_NOW, + NULL)); + ASSERT_OK(req.result); + uv_fs_req_cleanup(&req); + check_utime(path, atime, UV_FS_UTIME_NOW, /* test_lutime */ 0); + atime = mtime = 1291404900; /* 2010-12-03 20:35:00 - mees <3 */ checkme.atime = atime; @@ -2888,20 +3038,50 @@ TEST_IMPL(fs_lutime) { /* Test the synchronous version. */ atime = mtime = 400497753.25; /* 1982-09-10 11:22:33.25 */ - checkme.atime = atime; - checkme.mtime = mtime; - checkme.path = symlink_path; - req.data = &checkme; - r = uv_fs_lutime(NULL, &req, symlink_path, atime, mtime, NULL); -#if (defined(_AIX) && !defined(_AIX71)) || \ - defined(__MVS__) +#if (defined(_AIX) && !defined(_AIX71)) || defined(__MVS__) ASSERT_EQ(r, UV_ENOSYS); RETURN_SKIP("lutime is not implemented for z/OS and AIX versions below 7.1"); #endif ASSERT_OK(r); - lutime_cb(&req); - ASSERT_EQ(1, lutime_cb_count); + ASSERT_OK(req.result); + uv_fs_req_cleanup(&req); + check_utime(symlink_path, atime, mtime, /* test_lutime */ 1); + + ASSERT_OK(uv_fs_lutime(NULL, + &req, + symlink_path, + UV_FS_UTIME_OMIT, + UV_FS_UTIME_OMIT, + NULL)); + ASSERT_OK(req.result); + uv_fs_req_cleanup(&req); + check_utime(symlink_path, atime, mtime, /* test_lutime */ 1); + + ASSERT_OK(uv_fs_lutime(NULL, + &req, + symlink_path, + UV_FS_UTIME_NOW, + UV_FS_UTIME_OMIT, + NULL)); + ASSERT_OK(req.result); + uv_fs_req_cleanup(&req); + check_utime(symlink_path, UV_FS_UTIME_NOW, mtime, /* test_lutime */ 1); + + ASSERT_OK(uv_fs_lutime(NULL, &req, symlink_path, atime, mtime, NULL)); + ASSERT_OK(req.result); + uv_fs_req_cleanup(&req); + check_utime(symlink_path, atime, mtime, /* test_lutime */ 1); + + ASSERT_OK(uv_fs_lutime(NULL, + &req, + symlink_path, + UV_FS_UTIME_OMIT, + UV_FS_UTIME_NOW, + NULL)); + ASSERT_OK(req.result); + uv_fs_req_cleanup(&req); + check_utime(symlink_path, atime, UV_FS_UTIME_NOW, /* test_lutime */ 1); /* Test the asynchronous version. */ atime = mtime = 1291404900; /* 2010-12-03 20:35:00 */ @@ -2909,11 +3089,12 @@ TEST_IMPL(fs_lutime) { checkme.atime = atime; checkme.mtime = mtime; checkme.path = symlink_path; + req.data = &checkme; r = uv_fs_lutime(loop, &req, symlink_path, atime, mtime, lutime_cb); ASSERT_OK(r); uv_run(loop, UV_RUN_DEFAULT); - ASSERT_EQ(2, lutime_cb_count); + ASSERT_EQ(1, lutime_cb_count); /* Cleanup. */ unlink(path); @@ -4507,6 +4688,60 @@ TEST_IMPL(fs_open_readonly_acl) { MAKE_VALGRIND_HAPPY(loop); return 0; } + +TEST_IMPL(fs_stat_no_permission) { + uv_passwd_t pwd; + uv_fs_t req; + int r; + char* filename = "test_file_no_permission.txt"; + + /* Setup - clear the ACL and remove the file */ + loop = uv_default_loop(); + r = uv_os_get_passwd(&pwd); + ASSERT_OK(r); + call_icacls("icacls %s /remove *S-1-1-0:(F)", filename); + unlink(filename); + + /* Create the file */ + r = uv_fs_open(loop, + &open_req1, + filename, + UV_FS_O_RDONLY | UV_FS_O_CREAT, + S_IRUSR, + NULL); + ASSERT_GE(r, 0); + ASSERT_GE(open_req1.result, 0); + uv_fs_req_cleanup(&open_req1); + r = uv_fs_close(NULL, &close_req, open_req1.result, NULL); + ASSERT_OK(r); + ASSERT_OK(close_req.result); + uv_fs_req_cleanup(&close_req); + + /* Set up ACL */ + r = call_icacls("icacls %s /deny *S-1-1-0:(F)", filename); + if (r != 0) { + goto acl_cleanup; + } + + /* Read file stats */ + r = uv_fs_stat(NULL, &req, filename, NULL); + if (r != 0) { + goto acl_cleanup; + } + + uv_fs_req_cleanup(&req); + + acl_cleanup: + /* Cleanup */ + call_icacls("icacls %s /reset", filename); + uv_fs_unlink(NULL, &unlink_req, filename, NULL); + uv_fs_req_cleanup(&unlink_req); + unlink(filename); + uv_os_free_passwd(&pwd); + ASSERT_OK(r); + MAKE_VALGRIND_HAPPY(loop); + return 0; +} #endif #ifdef _WIN32 diff --git a/deps/uv/test/test-idna.c b/deps/uv/test/test-idna.c index 28f9eaaae9e77a..46df9f3c581015 100644 --- a/deps/uv/test/test-idna.c +++ b/deps/uv/test/test-idna.c @@ -39,7 +39,7 @@ TEST_IMPL(utf8_decode1) { /* Two-byte sequences. */ p = b; - snprintf(b, sizeof(b), "\xC2\x80\xDF\xBF"); + snprintf(b, sizeof(b), "%s", "\xC2\x80\xDF\xBF"); ASSERT_EQ(128, uv__utf8_decode1(&p, b + sizeof(b))); ASSERT_PTR_EQ(p, b + 2); ASSERT_EQ(0x7FF, uv__utf8_decode1(&p, b + sizeof(b))); @@ -47,7 +47,7 @@ TEST_IMPL(utf8_decode1) { /* Three-byte sequences. */ p = b; - snprintf(b, sizeof(b), "\xE0\xA0\x80\xEF\xBF\xBF"); + snprintf(b, sizeof(b), "%s", "\xE0\xA0\x80\xEF\xBF\xBF"); ASSERT_EQ(0x800, uv__utf8_decode1(&p, b + sizeof(b))); ASSERT_PTR_EQ(p, b + 3); ASSERT_EQ(0xFFFF, uv__utf8_decode1(&p, b + sizeof(b))); @@ -55,7 +55,7 @@ TEST_IMPL(utf8_decode1) { /* Four-byte sequences. */ p = b; - snprintf(b, sizeof(b), "\xF0\x90\x80\x80\xF4\x8F\xBF\xBF"); + snprintf(b, sizeof(b), "%s", "\xF0\x90\x80\x80\xF4\x8F\xBF\xBF"); ASSERT_EQ(0x10000, uv__utf8_decode1(&p, b + sizeof(b))); ASSERT_PTR_EQ(p, b + 4); ASSERT_EQ(0x10FFFF, uv__utf8_decode1(&p, b + sizeof(b))); @@ -63,7 +63,7 @@ TEST_IMPL(utf8_decode1) { /* Four-byte sequences > U+10FFFF; disallowed. */ p = b; - snprintf(b, sizeof(b), "\xF4\x90\xC0\xC0\xF7\xBF\xBF\xBF"); + snprintf(b, sizeof(b), "%s", "\xF4\x90\xC0\xC0\xF7\xBF\xBF\xBF"); ASSERT_EQ((unsigned) -1, uv__utf8_decode1(&p, b + sizeof(b))); ASSERT_PTR_EQ(p, b + 4); ASSERT_EQ((unsigned) -1, uv__utf8_decode1(&p, b + sizeof(b))); @@ -71,7 +71,7 @@ TEST_IMPL(utf8_decode1) { /* Overlong; disallowed. */ p = b; - snprintf(b, sizeof(b), "\xC0\x80\xC1\x80"); + snprintf(b, sizeof(b), "%s", "\xC0\x80\xC1\x80"); ASSERT_EQ((unsigned) -1, uv__utf8_decode1(&p, b + sizeof(b))); ASSERT_PTR_EQ(p, b + 2); ASSERT_EQ((unsigned) -1, uv__utf8_decode1(&p, b + sizeof(b))); @@ -79,7 +79,7 @@ TEST_IMPL(utf8_decode1) { /* Surrogate pairs; disallowed. */ p = b; - snprintf(b, sizeof(b), "\xED\xA0\x80\xED\xA3\xBF"); + snprintf(b, sizeof(b), "%s", "\xED\xA0\x80\xED\xA3\xBF"); ASSERT_EQ((unsigned) -1, uv__utf8_decode1(&p, b + sizeof(b))); ASSERT_PTR_EQ(p, b + 3); ASSERT_EQ((unsigned) -1, uv__utf8_decode1(&p, b + sizeof(b))); @@ -87,7 +87,7 @@ TEST_IMPL(utf8_decode1) { /* Simply illegal. */ p = b; - snprintf(b, sizeof(b), "\xF8\xF9\xFA\xFB\xFC\xFD\xFE\xFF"); + snprintf(b, sizeof(b), "%s", "\xF8\xF9\xFA\xFB\xFC\xFD\xFE\xFF"); for (i = 1; i <= 8; i++) { ASSERT_EQ((unsigned) -1, uv__utf8_decode1(&p, b + sizeof(b))); @@ -218,3 +218,15 @@ TEST_IMPL(idna_toascii) { #undef T #endif /* __MVS__ */ + +TEST_IMPL(wtf8) { + static const char input[] = "ᜄȺy𐞲:𞢢𘴇𐀀'¥3̞[ +#include + +static int limit; +static int alloc; + +static void* t_realloc(void* p, size_t n) { + alloc += n; + if (alloc > limit) + return NULL; + p = realloc(p, n); + ASSERT_NOT_NULL(p); + return p; +} + +static void* t_calloc(size_t m, size_t n) { + return t_realloc(NULL, m * n); +} + +static void* t_malloc(size_t n) { + return t_realloc(NULL, n); +} + +TEST_IMPL(loop_init_oom) { + uv_loop_t loop; + int err; + + ASSERT_OK(uv_replace_allocator(t_malloc, t_realloc, t_calloc, free)); + for (;;) { + err = uv_loop_init(&loop); + if (err == 0) + break; + ASSERT_EQ(err, UV_ENOMEM); + limit += 8; + alloc = 0; + } + ASSERT_OK(uv_loop_close(&loop)); + return 0; +} diff --git a/deps/uv/test/test-pipe-getsockname.c b/deps/uv/test/test-pipe-getsockname.c index 34b572343c698a..3be30e674182f2 100644 --- a/deps/uv/test/test-pipe-getsockname.c +++ b/deps/uv/test/test-pipe-getsockname.c @@ -59,7 +59,7 @@ static void pipe_client_connect_cb(uv_connect_t* req, int status) { ASSERT_OK(r); if (*buf == '\0') { /* Linux abstract socket. */ - const char expected[] = "\0" TEST_PIPENAME; + const char expected[] = "\0" TEST_PIPENAME "\0"; ASSERT_EQ(len, sizeof(expected) - 1); ASSERT_MEM_EQ(buf, expected, len); } else { @@ -154,6 +154,15 @@ TEST_IMPL(pipe_getsockname) { ASSERT_STR_EQ(pipe_server.pipe_fname, TEST_PIPENAME); #endif + r = uv_pipe_getsockname(&pipe_server, NULL, &len); + ASSERT_EQ(r, UV_EINVAL); + + r = uv_pipe_getsockname(&pipe_server, buf, NULL); + ASSERT_EQ(r, UV_EINVAL); + + r = uv_pipe_getsockname(&pipe_server, NULL, NULL); + ASSERT_EQ(r, UV_EINVAL); + len = sizeof(TEST_PIPENAME) - 1; ASSERT_EQ(UV_ENOBUFS, uv_pipe_getsockname(&pipe_server, buf, &len)); @@ -214,7 +223,7 @@ TEST_IMPL(pipe_getsockname) { TEST_IMPL(pipe_getsockname_abstract) { /* TODO(bnoordhuis) Use unique name, susceptible to concurrent test runs. */ - static const char name[] = "\0" TEST_PIPENAME; + static const char name[] = "\0" TEST_PIPENAME "\0"; #if defined(__linux__) char buf[256]; size_t buflen; diff --git a/deps/uv/test/test-platform-output.c b/deps/uv/test/test-platform-output.c index 4e5300da037399..06a8e484dd78ec 100644 --- a/deps/uv/test/test-platform-output.c +++ b/deps/uv/test/test-platform-output.c @@ -236,5 +236,24 @@ TEST_IMPL(platform_output) { printf(" version: %s\n", uname.version); printf(" machine: %s\n", uname.machine); + err = uv_getrusage_thread(&rusage); + if (err != UV_ENOTSUP) { + ASSERT_OK(err); + ASSERT_UINT64_GE(rusage.ru_utime.tv_sec, 0); + ASSERT_UINT64_GE(rusage.ru_utime.tv_usec, 0); + ASSERT_UINT64_GE(rusage.ru_stime.tv_sec, 0); + ASSERT_UINT64_GE(rusage.ru_stime.tv_usec, 0); + printf("uv_getrusage_thread:\n"); + printf(" user: %llu sec %llu microsec\n", + (unsigned long long) rusage.ru_utime.tv_sec, + (unsigned long long) rusage.ru_utime.tv_usec); + printf(" system: %llu sec %llu microsec\n", + (unsigned long long) rusage.ru_stime.tv_sec, + (unsigned long long) rusage.ru_stime.tv_usec); + printf(" page faults: %llu\n", (unsigned long long) rusage.ru_majflt); + printf(" maximum resident set size: %llu\n", + (unsigned long long) rusage.ru_maxrss); + } + return 0; } diff --git a/deps/uv/test/test-spawn.c b/deps/uv/test/test-spawn.c index efbb2395ff8b2b..964c8a86c76eb6 100644 --- a/deps/uv/test/test-spawn.c +++ b/deps/uv/test/test-spawn.c @@ -1329,9 +1329,7 @@ TEST_IMPL(environment_creation) { } } if (prev) { /* verify sort order */ -#if !defined(__MINGW32__) || defined(__MINGW64_VERSION_MAJOR) ASSERT_EQ(1, CompareStringOrdinal(prev, -1, str, -1, TRUE)); -#endif } ASSERT(found); /* verify that we expected this variable */ } @@ -1524,7 +1522,7 @@ TEST_IMPL(spawn_setuid_fails) { init_process_options("spawn_helper1", fail_cb); options.flags |= UV_PROCESS_SETUID; - /* On IBMi PASE, there is no root user. User may grant + /* On IBMi PASE, there is no root user. User may grant * root-like privileges, including setting uid to 0. */ #if defined(__PASE__) @@ -1575,7 +1573,7 @@ TEST_IMPL(spawn_setgid_fails) { init_process_options("spawn_helper1", fail_cb); options.flags |= UV_PROCESS_SETGID; - /* On IBMi PASE, there is no root user. User may grant + /* On IBMi PASE, there is no root user. User may grant * root-like privileges, including setting gid to 0. */ #if defined(__MVS__) || defined(__PASE__) diff --git a/deps/uv/test/test-thread-name.c b/deps/uv/test/test-thread-name.c new file mode 100644 index 00000000000000..39340744290a0e --- /dev/null +++ b/deps/uv/test/test-thread-name.c @@ -0,0 +1,193 @@ +/* Copyright libuv project contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" +#include "../src/uv-common.h" + +#include + +struct semaphores { + uv_sem_t main; + uv_sem_t worker; +}; + +static void thread_run(void* arg) { + int r; + char thread_name[16]; + struct semaphores* sem; + uv_thread_t thread; + + sem = arg; + +#ifdef _WIN32 + /* uv_thread_self isn't defined for the main thread on Windows. */ + thread = GetCurrentThread(); +#else + thread = uv_thread_self(); +#endif + + r = uv_thread_setname("worker-thread"); + ASSERT_OK(r); + + uv_sem_post(&sem->worker); + + r = uv_thread_getname(&thread, thread_name, sizeof(thread_name)); + ASSERT_OK(r); + + ASSERT_STR_EQ(thread_name, "worker-thread"); + + uv_sem_wait(&sem->main); +} + +TEST_IMPL(thread_name) { + int r; + uv_thread_t threads[2]; + char tn[UV_PTHREAD_MAX_NAMELEN_NP]; + char thread_name[UV_PTHREAD_MAX_NAMELEN_NP]; + char long_thread_name[UV_PTHREAD_MAX_NAMELEN_NP + 1]; + struct semaphores sem; + +#if defined(__ANDROID_API__) && __ANDROID_API__ < 26 || \ + defined(_AIX) || \ + defined(__MVS__) || \ + defined(__PASE__) + RETURN_SKIP("API not available on this platform"); +#endif + + ASSERT_OK(uv_sem_init(&sem.main, 0)); + ASSERT_OK(uv_sem_init(&sem.worker, 0)); + + memset(thread_name, 'a', sizeof(thread_name) - 1); + thread_name[sizeof(thread_name) - 1] = '\0'; + + memset(long_thread_name, 'a', sizeof(long_thread_name) - 1); + long_thread_name[sizeof(long_thread_name) - 1] = '\0'; + +#ifdef _WIN32 + /* uv_thread_self isn't defined for the main thread on Windows. */ + threads[0] = GetCurrentThread(); +#else + threads[0] = uv_thread_self(); +#endif + + r = uv_thread_getname(&threads[0], tn, sizeof(tn)); + ASSERT_OK(r); + + r = uv_thread_setname(long_thread_name); + ASSERT_OK(r); + + r = uv_thread_getname(&threads[0], tn, sizeof(tn)); + ASSERT_OK(r); + ASSERT_STR_EQ(tn, thread_name); + + r = uv_thread_setname(thread_name); + ASSERT_OK(r); + + r = uv_thread_getname(&threads[0], tn, sizeof(tn)); + ASSERT_OK(r); + ASSERT_STR_EQ(tn, thread_name); + + r = uv_thread_getname(&threads[0], tn, 3); + ASSERT_OK(r); + ASSERT_EQ(strlen(tn), 2); + ASSERT_OK(memcmp(thread_name, tn, 2)); + + /* Illumos doesn't support non-ASCII thread names. */ +#ifndef __illumos__ + r = uv_thread_setname("~½¬{½"); + ASSERT_OK(r); + + r = uv_thread_getname(&threads[0], tn, sizeof(tn)); + ASSERT_OK(r); + ASSERT_STR_EQ(tn, "~½¬{½"); +#endif + + ASSERT_OK(uv_thread_create(threads + 1, thread_run, &sem)); + + uv_sem_wait(&sem.worker); + + r = uv_thread_getname(threads + 1, tn, sizeof(tn)); + ASSERT_OK(r); + + ASSERT_STR_EQ(tn, "worker-thread"); + + uv_sem_post(&sem.main); + + ASSERT_OK(uv_thread_join(threads + 1)); + + uv_sem_destroy(&sem.main); + uv_sem_destroy(&sem.worker); + + return 0; +} + +#define MAX_THREADS 4 + +static void* executedThreads[MAX_THREADS] = { NULL }; +static int size; +static uv_loop_t* loop; + +static unsigned short int key_exists(void* key) { + size_t i; + for (i = 0; i < MAX_THREADS; i++) { + if (executedThreads[i] == key) { + return 1; + } + } + return 0; +} + +static void work_cb(uv_work_t* req) { + uv_thread_t thread = uv_thread_self(); + req->data = &thread; + char tn[UV_PTHREAD_MAX_NAMELEN_NP]; + ASSERT_OK(uv_thread_getname(&thread, tn, sizeof(tn))); + ASSERT_STR_EQ(tn, "libuv-worker"); +} + +static void after_work_cb(uv_work_t* req, int status) { + ASSERT_OK(status); + if (!key_exists(req->data)) { + executedThreads[size++] = req->data; + } + + if (size == MAX_THREADS) { + return; + } + + uv_queue_work(loop, req, work_cb, after_work_cb); +} + +TEST_IMPL(thread_name_threadpool) { + +#if defined(_AIX) || defined(__PASE__) + RETURN_SKIP("API not available on this platform"); +#endif + uv_work_t req; + loop = uv_default_loop(); + // Just to make sure all workers will be executed + // with the correct thread name + ASSERT_OK(uv_queue_work(loop, &req, work_cb, after_work_cb)); + uv_run(loop, UV_RUN_DEFAULT); + MAKE_VALGRIND_HAPPY(uv_default_loop()); + return 0; +} diff --git a/deps/uv/test/test-thread.c b/deps/uv/test/test-thread.c index d0094e304435bb..819bbd5c92399d 100644 --- a/deps/uv/test/test-thread.c +++ b/deps/uv/test/test-thread.c @@ -294,3 +294,13 @@ TEST_IMPL(thread_stack_size_explicit) { return 0; } + +static void thread_detach_cb(void* arg) {} + +TEST_IMPL(thread_detach) { + uv_thread_t thread; + ASSERT_OK(uv_thread_create(&thread, thread_detach_cb, NULL)); + ASSERT_OK(uv_thread_detach(&thread)); + + return 0; +} diff --git a/deps/uv/test/test-tty-duplicate-key.c b/deps/uv/test/test-tty-duplicate-key.c index 871d580266ad8d..e3e813e69b3536 100644 --- a/deps/uv/test/test-tty-duplicate-key.c +++ b/deps/uv/test/test-tty-duplicate-key.c @@ -131,7 +131,7 @@ static void make_key_event_records(WORD virt_key, DWORD ctr_key_state, # undef KEV } -TEST_IMPL(tty_duplicate_vt100_fn_key) { +TEST_IMPL(tty_duplicate_vt100_fn_key_libuv) { int r; int ttyin_fd; uv_tty_t tty_in; @@ -163,6 +163,10 @@ TEST_IMPL(tty_duplicate_vt100_fn_key) { r = uv_read_start((uv_stream_t*)&tty_in, tty_alloc, tty_read); ASSERT_OK(r); + /* + * libuv has chosen to emit ESC[[A, but other terminals, and even + * Windows itself use a different escape sequence, see the test below. + */ expect_str = ESC"[[A"; expect_nread = strlen(expect_str); @@ -184,6 +188,62 @@ TEST_IMPL(tty_duplicate_vt100_fn_key) { return 0; } +TEST_IMPL(tty_duplicate_vt100_fn_key_winvt) { + int r; + int ttyin_fd; + uv_tty_t tty_in; + uv_loop_t* loop; + HANDLE handle; + INPUT_RECORD records[2]; + DWORD written; + + loop = uv_default_loop(); + + /* Make sure we have an FD that refers to a tty */ + handle = CreateFileA("conin$", + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL); + ASSERT_PTR_NE(handle, INVALID_HANDLE_VALUE); + ttyin_fd = _open_osfhandle((intptr_t) handle, 0); + ASSERT_GE(ttyin_fd, 0); + ASSERT_EQ(UV_TTY, uv_guess_handle(ttyin_fd)); + + r = uv_tty_init(uv_default_loop(), &tty_in, ttyin_fd, 1); /* Readable. */ + ASSERT_OK(r); + ASSERT(uv_is_readable((uv_stream_t*) &tty_in)); + ASSERT(!uv_is_writable((uv_stream_t*) &tty_in)); + + r = uv_read_start((uv_stream_t*)&tty_in, tty_alloc, tty_read); + ASSERT_OK(r); + + /* + * Some keys, like F1, get are assigned a different value by Windows + * in ENABLE_VIRTUAL_TERMINAL_INPUT mode vs. libuv in the test above. + */ + expect_str = ESC"OP"; + expect_nread = strlen(expect_str); + + /* Turn on raw mode. */ + r = uv_tty_set_mode(&tty_in, UV_TTY_MODE_RAW_VT); + ASSERT_OK(r); + + /* + * Send F1 keystroke. + */ + make_key_event_records(VK_F1, 0, TRUE, records); + WriteConsoleInputW(handle, records, ARRAY_SIZE(records), &written); + ASSERT_EQ(written, ARRAY_SIZE(records)); + + uv_run(loop, UV_RUN_DEFAULT); + + MAKE_VALGRIND_HAPPY(loop); + return 0; +} + TEST_IMPL(tty_duplicate_alt_modifier_key) { int r; int ttyin_fd; diff --git a/deps/uv/test/test-udp-mmsg.c b/deps/uv/test/test-udp-mmsg.c index c0e000b9d92bbf..73213c43d97aa2 100644 --- a/deps/uv/test/test-udp-mmsg.c +++ b/deps/uv/test/test-udp-mmsg.c @@ -32,12 +32,12 @@ #define BUFFER_MULTIPLIER 20 #define MAX_DGRAM_SIZE (64 * 1024) #define NUM_SENDS 40 -#define EXPECTED_MMSG_ALLOCS (NUM_SENDS / BUFFER_MULTIPLIER) static uv_udp_t recver; static uv_udp_t sender; static int recv_cb_called; static int received_datagrams; +static int read_bytes; static int close_cb_called; static int alloc_cb_called; @@ -74,6 +74,7 @@ static void recv_cb(uv_udp_t* handle, const struct sockaddr* addr, unsigned flags) { ASSERT_GE(nread, 0); + read_bytes += nread; /* free and return if this is a mmsg free-only callback invocation */ if (flags & UV_UDP_MMSG_FREE) { @@ -140,7 +141,7 @@ TEST_IMPL(udp_mmsg) { /* On platforms that don't support mmsg, each recv gets its own alloc */ if (uv_udp_using_recvmmsg(&recver)) - ASSERT_EQ(alloc_cb_called, EXPECTED_MMSG_ALLOCS); + ASSERT_EQ(read_bytes, NUM_SENDS * 4); /* we're sending 4 bytes per datagram */ else ASSERT_EQ(alloc_cb_called, recv_cb_called); diff --git a/deps/uv/test/test-udp-multicast-join.c b/deps/uv/test/test-udp-multicast-join.c index 9e322dc579fc33..58b055561c6ded 100644 --- a/deps/uv/test/test-udp-multicast-join.c +++ b/deps/uv/test/test-udp-multicast-join.c @@ -36,10 +36,9 @@ static uv_udp_t client; static uv_udp_send_t req; static uv_udp_send_t req_ss; +static int darwin_ebusy_errors; static int cl_recv_cb_called; - static int sv_send_cb_called; - static int close_cb_called; static void alloc_cb(uv_handle_t* handle, @@ -128,6 +127,13 @@ static void cl_recv_cb(uv_udp_t* handle, #if !defined(__NetBSD__) r = uv_udp_set_source_membership(&server, MULTICAST_ADDR, NULL, source_addr, UV_JOIN_GROUP); +#if defined(__APPLE__) + if (r == UV_EBUSY) { + uv_close((uv_handle_t*) &server, close_cb); + darwin_ebusy_errors++; + return; + } +#endif ASSERT_OK(r); #endif @@ -160,7 +166,13 @@ TEST_IMPL(udp_multicast_join) { r = uv_udp_set_membership(&server, MULTICAST_ADDR, NULL, UV_JOIN_GROUP); if (r == UV_ENODEV) RETURN_SKIP("No multicast support."); + if (r == UV_ENOEXEC) + RETURN_SKIP("No multicast support (likely a firewall issue)."); ASSERT_OK(r); +#if defined(__ANDROID__) + /* It returns an ENOSYS error */ + RETURN_SKIP("Test does not currently work in ANDROID"); +#endif r = uv_udp_recv_start(&server, alloc_cb, cl_recv_cb); ASSERT_OK(r); @@ -175,6 +187,9 @@ TEST_IMPL(udp_multicast_join) { /* run the loop till all events are processed */ uv_run(uv_default_loop(), UV_RUN_DEFAULT); + if (darwin_ebusy_errors > 0) + RETURN_SKIP("Unexplained macOS IP_ADD_SOURCE_MEMBERSHIP EBUSY bug"); + ASSERT_EQ(2, cl_recv_cb_called); ASSERT_EQ(2, sv_send_cb_called); ASSERT_EQ(2, close_cb_called); diff --git a/deps/uv/test/test-udp-multicast-join6.c b/deps/uv/test/test-udp-multicast-join6.c index c6872e4283247d..430e4e3321e859 100644 --- a/deps/uv/test/test-udp-multicast-join6.c +++ b/deps/uv/test/test-udp-multicast-join6.c @@ -33,6 +33,7 @@ #if defined(__APPLE__) || \ defined(_AIX) || \ defined(__MVS__) || \ + defined(__FreeBSD__) || \ defined(__NetBSD__) || \ defined(__OpenBSD__) #define MULTICAST_ADDR "ff02::1%lo0" diff --git a/deps/uv/test/test-udp-try-send.c b/deps/uv/test/test-udp-try-send.c index 0c76fb1c84df68..6181fbbbffca3b 100644 --- a/deps/uv/test/test-udp-try-send.c +++ b/deps/uv/test/test-udp-try-send.c @@ -60,8 +60,6 @@ static void sv_recv_cb(uv_udp_t* handle, const uv_buf_t* rcvbuf, const struct sockaddr* addr, unsigned flags) { - ASSERT_GT(nread, 0); - if (nread == 0) { ASSERT_NULL(addr); return; @@ -70,11 +68,17 @@ static void sv_recv_cb(uv_udp_t* handle, ASSERT_EQ(4, nread); ASSERT_NOT_NULL(addr); - ASSERT_OK(memcmp("EXIT", rcvbuf->base, nread)); - uv_close((uv_handle_t*) handle, close_cb); - uv_close((uv_handle_t*) &client, close_cb); + if (!memcmp("EXIT", rcvbuf->base, nread)) { + uv_close((uv_handle_t*) handle, close_cb); + uv_close((uv_handle_t*) &client, close_cb); + } else { + ASSERT_MEM_EQ(rcvbuf->base, "HELO", 4); + } sv_recv_cb_called++; + + if (sv_recv_cb_called == 2) + uv_udp_recv_stop(handle); } @@ -101,9 +105,33 @@ TEST_IMPL(udp_try_send) { ASSERT_OK(r); buf = uv_buf_init(buffer, sizeof(buffer)); + + r = uv_udp_try_send(&client, &buf, 0, (const struct sockaddr*) &addr); + ASSERT_EQ(r, UV_EINVAL); + r = uv_udp_try_send(&client, &buf, 1, (const struct sockaddr*) &addr); ASSERT_EQ(r, UV_EMSGSIZE); + uv_buf_t* bufs[] = {&buf, &buf}; + unsigned int nbufs[] = {1, 1}; + struct sockaddr* addrs[] = { + (struct sockaddr*) &addr, + (struct sockaddr*) &addr, + }; + + ASSERT_EQ(0, sv_recv_cb_called); + + buf = uv_buf_init("HELO", 4); + r = uv_udp_try_send2(&client, 2, bufs, nbufs, addrs, /*flags*/0); + ASSERT_EQ(r, 2); + + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + + ASSERT_EQ(2, sv_recv_cb_called); + + r = uv_udp_recv_start(&server, alloc_cb, sv_recv_cb); + ASSERT_OK(r); + buf = uv_buf_init("EXIT", 4); r = uv_udp_try_send(&client, &buf, 1, (const struct sockaddr*) &addr); ASSERT_EQ(4, r); @@ -111,7 +139,7 @@ TEST_IMPL(udp_try_send) { uv_run(uv_default_loop(), UV_RUN_DEFAULT); ASSERT_EQ(2, close_cb_called); - ASSERT_EQ(1, sv_recv_cb_called); + ASSERT_EQ(3, sv_recv_cb_called); ASSERT_OK(client.send_queue_size); ASSERT_OK(server.send_queue_size); diff --git a/deps/uv/uv.gyp b/deps/uv/uv.gyp index 8c8d7d00fd2913..540445f1f3249b 100644 --- a/deps/uv/uv.gyp +++ b/deps/uv/uv.gyp @@ -173,7 +173,7 @@ ], 'include_dirs': [ 'include' ], 'conditions': [ - ['OS == "linux"', { + ['OS == "linux" or OS=="openharmony"', { 'defines': [ '_POSIX_C_SOURCE=200112' ], }], ], @@ -190,7 +190,7 @@ '-Wno-unused-parameter', '-Wstrict-prototypes', ], - 'OTHER_CFLAGS': [ '-g', '--std=gnu89' ], + 'OTHER_CFLAGS': [ '-g', '--std=gnu11' ], }, 'conditions': [ [ 'OS=="win"', { @@ -255,14 +255,14 @@ }], ], }], - [ 'OS in "linux mac ios android zos"', { + [ 'OS in "linux mac ios android zos openharmony"', { 'sources': [ 'src/unix/proctitle.c' ], }], [ 'OS != "zos"', { 'cflags': [ '-fvisibility=hidden', '-g', - '--std=gnu89', + '--std=gnu11', '-Wall', '-Wextra', '-Wno-unused-parameter', @@ -279,7 +279,7 @@ '_DARWIN_UNLIMITED_SELECT=1', ] }], - [ 'OS=="linux"', { + [ 'OS=="linux" or OS=="openharmony"', { 'defines': [ '_GNU_SOURCE' ], 'sources': [ '<@(uv_sources_linux)', diff --git a/deps/zlib/zlib.gyp b/deps/zlib/zlib.gyp index 92e20b64b039ae..dcf6bdb67f6b92 100644 --- a/deps/zlib/zlib.gyp +++ b/deps/zlib/zlib.gyp @@ -75,7 +75,7 @@ ['OS=="android"', { 'defines': [ 'ARMV8_OS_ANDROID' ], }], - ['OS=="linux"', { + ['OS=="linux" or OS=="openharmony"', { 'defines': [ 'ARMV8_OS_LINUX' ], }], ['OS=="mac"', { @@ -93,7 +93,7 @@ ['OS=="android"', { 'defines': [ 'ARMV8_OS_ANDROID' ], }], - ['OS=="linux"', { + ['OS=="linux" or OS=="openharmony"', { 'defines': [ 'ARMV8_OS_LINUX' ], }], ['OS=="mac"', { diff --git a/doc/api/assert.md b/doc/api/assert.md index 555d78dcbc03f2..fe093bfceda330 100644 --- a/doc/api/assert.md +++ b/doc/api/assert.md @@ -2587,10 +2587,12 @@ argument. -> Stability: 1.2 - Release candidate - * `actual` {any} * `expected` {any} * `message` {string|Error} diff --git a/doc/api/buffer.md b/doc/api/buffer.md index 181b0e3d8009e7..9cb6e540f41ef5 100644 --- a/doc/api/buffer.md +++ b/doc/api/buffer.md @@ -5277,10 +5277,12 @@ An alias for [`buffer.constants.MAX_STRING_LENGTH`][]. -> Stability: 1 - Experimental - * `id` {string} A `'blob:nodedata:...` URL string returned by a prior call to `URL.createObjectURL()`. * Returns: {Blob} diff --git a/doc/api/child_process.md b/doc/api/child_process.md index 2cf8b70f6a787d..89a1975b78b7e7 100644 --- a/doc/api/child_process.md +++ b/doc/api/child_process.md @@ -1446,8 +1446,10 @@ instances of `ChildProcess`. added: v0.7.7 --> -* `code` {number} The exit code if the child process exited on its own. -* `signal` {string} The signal by which the child process was terminated. +* `code` {number} The exit code if the child process exited on its own, or + `null` if the child process terminated due to a signal. +* `signal` {string} The signal by which the child process was terminated, or + `null` if the child process did not terminated due to a signal. The `'close'` event is emitted after a process has ended _and_ the stdio streams of a child process have been closed. This is distinct from the @@ -1455,6 +1457,11 @@ streams of a child process have been closed. This is distinct from the streams. The `'close'` event will always emit after [`'exit'`][] was already emitted, or [`'error'`][] if the child process failed to spawn. +If the process exited, `code` is the final exit code of the process, otherwise +`null`. If the process terminated due to receipt of a signal, `signal` is the +string name of the signal, otherwise `null`. One of the two will always be +non-`null`. + ```cjs const { spawn } = require('node:child_process'); const ls = spawn('ls', ['-lh', '/usr']); @@ -1524,8 +1531,10 @@ See also [`subprocess.kill()`][] and [`subprocess.send()`][]. added: v0.1.90 --> -* `code` {number} The exit code if the child process exited on its own. -* `signal` {string} The signal by which the child process was terminated. +* `code` {number} The exit code if the child process exited on its own, or + `null` if the child process terminated due to a signal. +* `signal` {string} The signal by which the child process was terminated, or + `null` if the child process did not terminated due to a signal. The `'exit'` event is emitted after the child process ends. If the process exited, `code` is the final exit code of the process, otherwise `null`. If the diff --git a/doc/api/cli.md b/doc/api/cli.md index 6f984926a62973..cc311472678108 100644 --- a/doc/api/cli.md +++ b/doc/api/cli.md @@ -195,6 +195,9 @@ process. -Enable [Source Map v3][Source Map] support for stack traces. +Enable [Source Map][] support for stack traces. When using a transpiler, such as TypeScript, stack traces thrown by an application reference the transpiled code, not the original source position. @@ -1236,6 +1236,17 @@ added: v22.4.0 Enable experimental [`Web Storage`][] support. +### `--experimental-worker-inspection` + + + +> Stability: 1.1 - Active Development + +Enable experimental support for the worker inspection with Chrome DevTools. + ### `--expose-gc` Regenerates the snapshot files used by the test runner for [snapshot testing][]. @@ -3046,6 +3058,10 @@ Use `--watch-path` to specify what paths to watch. This flag cannot be combined with `--check`, `--eval`, `--interactive`, or the REPL. +Note: The `--watch` flag requires a file path as an argument and is incompatible +with `--run` or inline script input, as `--run` takes precedence and ignores watch +mode. If no file is provided, Node.js will exit with status code `9`. + ```bash node --watch index.js ``` @@ -3071,6 +3087,9 @@ combination with `--watch`. This flag cannot be combined with `--check`, `--eval`, `--interactive`, `--test`, or the REPL. +Note: Using `--watch-path` implicitly enables `--watch`, which requires a file path +and is incompatible with `--run`, as `--run` takes precedence and ignores watch mode. + ```bash node --watch-path=./src --watch-path=./tests index.js ``` @@ -3831,7 +3850,7 @@ node --stack-trace-limit=12 -p -e "Error.stackTraceLimit" # prints 12 [REPL]: repl.md [ScriptCoverage]: https://chromedevtools.github.io/devtools-protocol/tot/Profiler#type-ScriptCoverage [ShadowRealm]: https://github.com/tc39/proposal-shadowrealm -[Source Map]: https://sourcemaps.info/spec.html +[Source Map]: https://tc39.es/ecma426/ [TypeScript type-stripping]: typescript.md#type-stripping [V8 Inspector integration for Node.js]: debugger.md#v8-inspector-integration-for-nodejs [V8 JavaScript code coverage]: https://v8project.blogspot.com/2017/12/javascript-code-coverage.html diff --git a/doc/api/corepack.md b/doc/api/corepack.md index 8bc9c134e2dc7c..b017f7570cb260 100644 --- a/doc/api/corepack.md +++ b/doc/api/corepack.md @@ -12,10 +12,9 @@ added: > Stability: 1 - Experimental -Documentation for this tool can be found on the [Corepack repository][]. +**Corepack will no longer be distributed starting with Node.js v25.** -Despite Corepack being distributed with default installs of Node.js, the package -managers managed by Corepack are not part of the Node.js distribution, and -Corepack itself will no longer be distributed with Node.js 25+. +Users currently depending on the bundled `corepack` executable from Node.js +can switch to using the userland-provided [corepack][] module. -[Corepack repository]: https://github.com/nodejs/corepack +[corepack]: https://github.com/nodejs/corepack diff --git a/doc/api/crypto.md b/doc/api/crypto.md index 33c6283171fc2b..1c74794ec54b90 100644 --- a/doc/api/crypto.md +++ b/doc/api/crypto.md @@ -2142,7 +2142,7 @@ added: v22.10.0 -* `algorithm`: {AlgorithmIdentifier|RsaHashedImportParams|EcKeyImportParams|HmacImportParams} +* `algorithm`: {string|Algorithm|RsaHashedImportParams|EcKeyImportParams|HmacImportParams} @@ -2647,7 +2647,23 @@ added: v15.6.0 * `otherCert` {X509Certificate} * Returns: {boolean} -Checks whether this certificate was issued by the given `otherCert`. +Checks whether this certificate was potentially issued by the given `otherCert` +by comparing the certificate metadata. + +This is useful for pruning a list of possible issuer certificates which have been +selected using a more rudimentary filtering routine, i.e. just based on subject +and issuer names. + +Finally, to verify that this certificate's signature was produced by a private key +corresponding to `otherCert`'s public key use [`x509.verify(publicKey)`][] +with `otherCert`'s public key represented as a [`KeyObject`][] +like so + +```js +if (!x509.verify(otherCert.publicKey)) { + throw new Error('otherCert did not issue x509'); +} +``` ### `x509.checkPrivateKey(privateKey)` @@ -3884,7 +3900,7 @@ console.log(key.export().toString('hex')); // e89..........41e The size of a generated HMAC key should not exceed the block size of the underlying hash function. See [`crypto.createHmac()`][] for more information. -### `crypto.generatePrime(size[, options[, callback]])` +### `crypto.generatePrime(size[, options], callback)` -Type: Runtime +Type: End-of-Life `Transform._transformState` will be removed in future versions where it is no longer required due to simplification of the implementation. @@ -3766,10 +3769,92 @@ of built-in modules. This was incomplete and matched the already deprecated `repl._builtinLibs` ([DEP0142][]) instead it's better to rely upon `require('node:module').builtinModules`. +### DEP0192: `require('node:_tls_common')` and `require('node:_tls_wrap')` + + + +Type: Documentation-only + +The `node:_tls_common` and `node:_tls_wrap` modules are deprecated as they should be considered +an internal nodejs implementation rather than a public facing API, use `node:tls` instead. + +### DEP0193: `require('node:_stream_*')` + + + +Type: Documentation-only + +The `node:_stream_duplex`, `node:_stream_passthrough`, `node:_stream_readable`, `node:_stream_transform`, +`node:_stream_wrap` and `node:_stream_writable` modules are deprecated as they should be considered +an internal nodejs implementation rather than a public facing API, use `node:stream` instead. + +### DEP0194: HTTP/2 priority signaling + + + +Type: Documentation-only + +The support for priority signaling has been deprecated in the [RFC 9113][], and +will be removed in future versions of Node.js. + +### DEP0195: Instantiating `node:http` classes without `new` + + + +Type: Documentation-only + +Instantiating classes without the `new` qualifier exported by the `node:http` module is deprecated. +It is recommended to use the `new` qualifier instead. This applies to all http classes, such as +`OutgoingMessage`, `IncomingMessage`, `ServerResponse` and `ClientRequest`. + +### DEP0196: Calling `node:child_process` functions with `options.shell` as an empty string + + + +Type: Documentation-only + +Calling the process-spawning functions with `{ shell: '' }` is almost certainly +unintentional, and can cause aberrant behavior. + +To make [`child_process.execFile`][] or [`child_process.spawn`][] invoke the +default shell, use `{ shell: true }`. If the intention is not to invoke a shell +(default behavior), either omit the `shell` option, or set it to `false` or a +nullish value. + +To make [`child_process.exec`][] invoke the default shell, either omit the +`shell` option, or set it to a nullish value. If the intention is not to invoke +a shell, use [`child_process.execFile`][] instead. + [DEP0142]: #dep0142-repl_builtinlibs [NIST SP 800-38D]: https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38d.pdf [RFC 6066]: https://tools.ietf.org/html/rfc6066#section-3 [RFC 8247 Section 2.4]: https://www.rfc-editor.org/rfc/rfc8247#section-2.4 +[RFC 9113]: https://datatracker.ietf.org/doc/html/rfc9113#section-5.3.1 [WHATWG URL API]: url.md#the-whatwg-url-api [`"exports"` or `"main"` entry]: packages.md#main-entry-point-export [`'uncaughtException'`]: process.md#event-uncaughtexception @@ -3796,6 +3881,7 @@ upon `require('node:module').builtinModules`. [`asyncResource.runInAsyncScope()`]: async_context.md#asyncresourceruninasyncscopefn-thisarg-args [`buffer.subarray`]: buffer.md#bufsubarraystart-end [`child_process.execFile`]: child_process.md#child_processexecfilefile-args-options-callback +[`child_process.exec`]: child_process.md#child_processexeccommand-options-callback [`child_process.spawn`]: child_process.md#child_processspawncommand-args-options [`child_process`]: child_process.md [`clearInterval()`]: timers.md#clearintervaltimeout diff --git a/doc/api/diagnostics_channel.md b/doc/api/diagnostics_channel.md index 49dc01fa85c171..7be2f947254a3c 100644 --- a/doc/api/diagnostics_channel.md +++ b/doc/api/diagnostics_channel.md @@ -1102,14 +1102,10 @@ for the sync error and one for the async error. ### Built-in Channels -> Stability: 1 - Experimental - -While the diagnostics\_channel API is now considered stable, the built-in -channels currently available are not. Each channel must be declared stable -independently. - #### Console +> Stability: 1 - Experimental + `console.log` * `args` {any\[]} @@ -1147,6 +1143,8 @@ passed to `console.error()`. #### HTTP +> Stability: 1 - Experimental + `http.client.request.created` * `request` {http.ClientRequest} @@ -1200,8 +1198,79 @@ The event is emitted before the response is sent. Emitted when server sends a response. +#### HTTP/2 + +> Stability: 1 - Experimental + +`http2.client.stream.created` + +* `stream` {ClientHttp2Stream} +* `headers` {HTTP/2 Headers Object} + +Emitted when a stream is created on the client. + +`http2.client.stream.start` + +* `stream` {ClientHttp2Stream} +* `headers` {HTTP/2 Headers Object} + +Emitted when a stream is started on the client. + +`http2.client.stream.error` + +* `stream` {ClientHttp2Stream} +* `error` {Error} + +Emitted when an error occurs during the processing of a stream on the client. + +`http2.client.stream.finish` + +* `stream` {ClientHttp2Stream} +* `headers` {HTTP/2 Headers Object} +* `flags` {number} + +Emitted when a stream is received on the client. + +`http2.client.stream.close` + +* `stream` {ClientHttp2Stream} + +Emitted when a stream is closed on the client. The HTTP/2 error code used when +closing the stream can be retrieved using the `stream.rstCode` property. + +`http2.server.stream.created` + +* `stream` {ServerHttp2Stream} +* `headers` {HTTP/2 Headers Object} + +Emitted when a stream is created on the server. + +`http2.server.stream.start` + +* `stream` {ServerHttp2Stream} +* `headers` {HTTP/2 Headers Object} + +Emitted when a stream is started on the server. + +`http2.server.stream.error` + +* `stream` {ServerHttp2Stream} +* `error` {Error} + +Emitted when an error occurs during the processing of a stream on the server. + +`http2.server.stream.finish` + +* `stream` {ServerHttp2Stream} +* `headers` {HTTP/2 Headers Object} +* `flags` {number} + +Emitted when a stream is sent on the server. + #### Modules +> Stability: 1 - Experimental + `module.require.start` * `event` {Object} containing the following properties @@ -1254,11 +1323,13 @@ Emitted when a `import()` throws an error. See [`error` event][]. #### NET +> Stability: 1 - Experimental + `net.client.socket` -* `socket` {net.Socket} +* `socket` {net.Socket|tls.TLSSocket} -Emitted when a new TCP or pipe client socket is created. +Emitted when a new TCP or pipe client socket connection is created. `net.server.socket` @@ -1288,6 +1359,8 @@ Emitted when [`net.Server.listen()`][] is returning an error. #### UDP +> Stability: 1 - Experimental + `udp.socket` * `socket` {dgram.Socket} @@ -1296,6 +1369,8 @@ Emitted when a new UDP socket is created. #### Process +> Stability: 1 - Experimental + @@ -1316,6 +1391,8 @@ Emitted when [`process.execve()`][] is invoked. #### Worker Thread +> Stability: 1 - Experimental + diff --git a/doc/api/errors.md b/doc/api/errors.md index efffacd18d39c7..1c54e2127f6d0b 100644 --- a/doc/api/errors.md +++ b/doc/api/errors.md @@ -1809,8 +1809,6 @@ time. ### `ERR_INPUT_TYPE_NOT_ALLOWED` -> Stability: 1 - Experimental - The `--input-type` flag was used to attempt to execute a file. This flag can only be used with input via `--eval`, `--print`, or `STDIN`. @@ -2978,6 +2976,15 @@ category. The `node:trace_events` module could not be loaded because Node.js was compiled with the `--without-v8-platform` flag. + + +### `ERR_TRAILING_JUNK_AFTER_STREAM_END` + +Trailing junk found after the end of the compressed stream. +This error is thrown when extra, unexpected data is detected +after the end of a compressed stream (for example, in zlib +or gzip decompression). + ### `ERR_TRANSFORM_ALREADY_TRANSFORMING` @@ -3050,8 +3057,6 @@ An invalid or unknown encoding option was passed to an API. ### `ERR_UNKNOWN_FILE_EXTENSION` -> Stability: 1 - Experimental - An attempt was made to load a module with an unknown or unsupported file extension. @@ -3059,8 +3064,6 @@ extension. ### `ERR_UNKNOWN_MODULE_FORMAT` -> Stability: 1 - Experimental - An attempt was made to load a module with an unknown or unsupported format. @@ -3136,8 +3139,6 @@ transformation with [type-stripping][]. ### `ERR_USE_AFTER_CLOSE` -> Stability: 1 - Experimental - An attempt was made to use something that was already closed. diff --git a/doc/api/events.md b/doc/api/events.md index f5d2239fe06256..87a52f00985e5a 100644 --- a/doc/api/events.md +++ b/doc/api/events.md @@ -603,10 +603,10 @@ myEmitter.emit('event', 1, 2, 3, 4, 5); added: v6.0.0 --> -* Returns: {Array} +* Returns: {string\[]|symbol\[]} Returns an array listing the events for which the emitter has registered -listeners. The values in the array are strings or `Symbol`s. +listeners. ```mjs import { EventEmitter } from 'node:events'; diff --git a/doc/api/fs.md b/doc/api/fs.md index 4d92bf2370bf7f..c70e38f71e7719 100644 --- a/doc/api/fs.md +++ b/doc/api/fs.md @@ -476,11 +476,17 @@ Reads data from the file and stores that in the given buffer. If the file is not modified concurrently, the end-of-file is reached when the number of bytes read is zero. -#### `filehandle.readableWebStream()` +#### `filehandle.readableWebStream([options])` -> Stability: 1 - Experimental - +* `options` {Object} + * `autoClose` {boolean} When true, causes the {FileHandle} to be closed when the + stream is closed. **Default:** `false` * Returns: {ReadableStream} Returns a byte-oriented `ReadableStream` that may be used to read the file's @@ -860,7 +867,8 @@ added: > Stability: 1 - Experimental -An alias for `filehandle.close()`. +Calls `filehandle.close()` and returns a promise that fulfills when the +filehandle is closed. ### `fsPromises.access(path[, mode])` @@ -1074,6 +1082,12 @@ behavior is similar to `cp dir1/ dir2/`. -> Stability: 1 - Experimental - * `pattern` {string|string\[]} * `options` {Object} - * `cwd` {string} current working directory. **Default:** `process.cwd()` + * `cwd` {string|URL} current working directory. **Default:** `process.cwd()` * `exclude` {Function|string\[]} Function to filter out files/directories or a list of glob patterns to be excluded. If a function is provided, return `true` to exclude the item, `false` to include it. **Default:** `undefined`. @@ -3126,6 +3138,12 @@ descriptor. See [`fs.utimes()`][]. -> Stability: 1 - Experimental - * `pattern` {string|string\[]} * `options` {Object} - * `cwd` {string} current working directory. **Default:** `process.cwd()` + * `cwd` {string|URL} current working directory. **Default:** `process.cwd()` * `exclude` {Function|string\[]} Function to filter out files/directories or a list of glob patterns to be excluded. If a function is provided, return `true` to exclude the item, `false` to include it. **Default:** `undefined`. @@ -3575,10 +3591,12 @@ Functions based on `fs.open()` exhibit this behavior as well: -> Stability: 1 - Experimental - * `path` {string|Buffer|URL} * `options` {Object} * `type` {string} An optional mime type for the blob. @@ -5674,6 +5692,12 @@ Synchronous version of [`fs.futimes()`][]. Returns `undefined`. -> Stability: 1 - Experimental - * `pattern` {string|string\[]} * `options` {Object} - * `cwd` {string} current working directory. **Default:** `process.cwd()` + * `cwd` {string|URL} current working directory. **Default:** `process.cwd()` * `exclude` {Function|string\[]} Function to filter out files/directories or a list of glob patterns to be excluded. If a function is provided, return `true` to exclude the item, `false` to include it. **Default:** `undefined`. @@ -6722,6 +6744,27 @@ provided by the operating system's underlying directory mechanisms. Entries added or removed while iterating over the directory might not be included in the iteration results. +#### `dir[Symbol.asyncDispose]()` + + + +> Stability: 1 - Experimental + +Calls `dir.close()` and returns a promise that fulfills when the +dir is closed. + +#### `dir[Symbol.Dispose]()` + + + +> Stability: 1 - Experimental + +Calls `dir.closeSync()` and returns `undefined`. + ### Class: `fs.Dirent` -> Stability: 1 - Experimental - * {string} The path to the parent directory of the file this {fs.Dirent} object refers to. diff --git a/doc/api/http.md b/doc/api/http.md index 19d0f017f5f920..6c42ea08a72f5d 100644 --- a/doc/api/http.md +++ b/doc/api/http.md @@ -3322,13 +3322,13 @@ const server = http.createServer((req, res) => { }); ``` -### `outgoingMessage.setTimeout(msesc[, callback])` +### `outgoingMessage.setTimeout(msecs[, callback])` -* `msesc` {number} +* `msecs` {number} * `callback` {Function} Optional function to be called when a timeout occurs. Same as binding to the `timeout` event. * Returns: {this} diff --git a/doc/api/http2.md b/doc/api/http2.md index e19b922fe08809..1f8fefa9d7be3b 100644 --- a/doc/api/http2.md +++ b/doc/api/http2.md @@ -1071,9 +1071,14 @@ The `'origin'` event is only emitted when using a secure TLS connection. -* `headers` {HTTP/2 Headers Object} +* `headers` {HTTP/2 Headers Object} | {Array} * `options` {Object} * `endStream` {boolean} `true` if the `Http2Stream` _writable_ side should @@ -1087,7 +1092,8 @@ added: v8.4.0 created stream is dependent on. * `weight` {number} Specifies the relative dependency of a stream in relation to other streams with the same `parent`. The value is a number between `1` - and `256` (inclusive). + and `256` (inclusive). This has been **deprecated** in [RFC 9113][], and + support for it will be removed in future versions of Node.js. * `waitForTrailers` {boolean} When `true`, the `Http2Stream` will emit the `'wantTrailers'` event after the final `DATA` frame has been sent. * `signal` {AbortSignal} An AbortSignal that may be used to abort an ongoing @@ -1457,8 +1463,12 @@ numeric stream identifier. +> Stability: 0 - Deprecated: support for priority signaling has been deprecated +> in the [RFC 9113][] and is no longer supported in Node.js. + * `options` {Object} * `exclusive` {boolean} When `true` and `parent` identifies a parent Stream, this stream is made the sole direct dependency of the parent, with @@ -1568,6 +1578,11 @@ req.setTimeout(5000, () => req.close(NGHTTP2_CANCEL)); Provides miscellaneous information about the current state of the @@ -1583,8 +1598,11 @@ Provides miscellaneous information about the current state of the remotely. * `sumDependencyWeight` {number} The sum weight of all `Http2Stream` instances that depend on this `Http2Stream` as specified using - `PRIORITY` frames. - * `weight` {number} The priority weight of this `Http2Stream`. + `PRIORITY` frames. This has been **deprecated** in [RFC 9113][], and + support for it will be removed in future versions of Node.js. + * `weight` {number} The priority weight of this `Http2Stream`. This has been + **deprecated** in [RFC 9113][], and support for it will be removed in future + versions of Node.js. A current state of this `Http2Stream`. @@ -2898,6 +2916,10 @@ changes: a server should wait when an [`'unknownProtocol'`][] is emitted. If the socket has not been destroyed by that time the server will destroy it. **Default:** `10000`. + * `strictFieldWhitespaceValidation` {boolean} If `true`, it turns on strict leading + and trailing whitespace validation for HTTP/2 header field names and values + as per [RFC-9113](https://www.rfc-editor.org/rfc/rfc9113.html#section-8.2.1). + **Default:** `true`. * ...: Any [`net.createServer()`][] option can be provided. * `onRequestHandler` {Function} See [Compatibility API][] * Returns: {Http2Server} @@ -3069,6 +3091,10 @@ changes: a server should wait when an [`'unknownProtocol'`][] event is emitted. If the socket has not been destroyed by that time the server will destroy it. **Default:** `10000`. + * `strictFieldWhitespaceValidation` {boolean} If `true`, it turns on strict leading + and trailing whitespace validation for HTTP/2 header field names and values + as per [RFC-9113](https://www.rfc-editor.org/rfc/rfc9113.html#section-8.2.1). + **Default:** `true`. * `onRequestHandler` {Function} See [Compatibility API][] * Returns: {Http2SecureServer} @@ -3224,6 +3250,10 @@ changes: a server should wait when an [`'unknownProtocol'`][] event is emitted. If the socket has not been destroyed by that time the server will destroy it. **Default:** `10000`. + * `strictFieldWhitespaceValidation` {boolean} If `true`, it turns on strict leading + and trailing whitespace validation for HTTP/2 header field names and values + as per [RFC-9113](https://www.rfc-editor.org/rfc/rfc9113.html#section-8.2.1). + **Default:** `true`. * `listener` {Function} Will be registered as a one-time listener of the [`'connect'`][] event. * Returns: {ClientHttp2Session} @@ -4880,6 +4910,7 @@ you need to implement any fall-back behavior yourself. [RFC 7838]: https://tools.ietf.org/html/rfc7838 [RFC 8336]: https://tools.ietf.org/html/rfc8336 [RFC 8441]: https://tools.ietf.org/html/rfc8441 +[RFC 9113]: https://datatracker.ietf.org/doc/html/rfc9113#section-5.3.1 [Sensitive headers]: #sensitive-headers [`'checkContinue'`]: #event-checkcontinue [`'connect'`]: #event-connect diff --git a/doc/api/inspector.md b/doc/api/inspector.md index ea5e9b032a46af..1021ac62d4b517 100644 --- a/doc/api/inspector.md +++ b/doc/api/inspector.md @@ -511,6 +511,19 @@ inspector.Network.requestWillBeSent({ }); ``` +### `inspector.Network.dataReceived([params])` + + + +* `params` {Object} + +This feature is only available with the `--experimental-network-inspection` flag enabled. + +Broadcasts the `Network.dataReceived` event to connected frontends, or buffers the data if +`Network.streamResourceContent` command was not invoked for the given request yet. + ### `inspector.Network.requestWillBeSent([params])` diff --git a/doc/api/n-api.md b/doc/api/n-api.md index 9daf8ef7697028..cf8fd25c6002e5 100644 --- a/doc/api/n-api.md +++ b/doc/api/n-api.md @@ -3683,6 +3683,8 @@ napi_status napi_get_value_string_latin1(napi_env env, is returned in `result`. * `[in] bufsize`: Size of the destination buffer. When this value is insufficient, the returned string is truncated and null-terminated. + If this value is zero, then the string is not returned and no changes are done + to the buffer. * `[out] result`: Number of bytes copied into the buffer, excluding the null terminator. @@ -3714,6 +3716,8 @@ napi_status napi_get_value_string_utf8(napi_env env, returned in `result`. * `[in] bufsize`: Size of the destination buffer. When this value is insufficient, the returned string is truncated and null-terminated. + If this value is zero, then the string is not returned and no changes are done + to the buffer. * `[out] result`: Number of bytes copied into the buffer, excluding the null terminator. @@ -3744,6 +3748,8 @@ napi_status napi_get_value_string_utf16(napi_env env, null terminator is returned. * `[in] bufsize`: Size of the destination buffer. When this value is insufficient, the returned string is truncated and null-terminated. + If this value is zero, then the string is not returned and no changes are done + to the buffer. * `[out] result`: Number of 2-byte code units copied into the buffer, excluding the null terminator. diff --git a/doc/api/permissions.md b/doc/api/permissions.md index c31ca5bbff2465..bccb0774274027 100644 --- a/doc/api/permissions.md +++ b/doc/api/permissions.md @@ -102,12 +102,29 @@ $ node --permission --allow-fs-read=* --allow-fs-write=* index.js Hello world! ``` +By default the entrypoints of your application are included +in the allowed file system read list. For example: + +```console +$ node --permission index.js +``` + +* `index.js` will be included in the allowed file system read list + +```console +$ node -r /path/to/custom-require.js --permission index.js. +``` + +* `/path/to/custom-require.js` will be included in the allowed file system read + list. +* `index.js` will be included in the allowed file system read list. + The valid arguments for both flags are: * `*` - To allow all `FileSystemRead` or `FileSystemWrite` operations, respectively. -* Paths delimited by comma (`,`) to allow only matching `FileSystemRead` or - `FileSystemWrite` operations, respectively. +* Relative paths to the current working directory. +* Absolute paths. Example: diff --git a/doc/api/process.md b/doc/api/process.md index 3b9341a4f54d66..40fb3b08cf5f59 100644 --- a/doc/api/process.md +++ b/doc/api/process.md @@ -976,6 +976,24 @@ $ bash -c 'exec -a customArgv0 ./node' 'customArgv0' ``` +## `process.availableMemory()` + + + +* {number} + +Gets the amount of free memory that is still available to the process +(in bytes). + +See [`uv_get_available_memory`][uv_get_available_memory] for more +information. + ## `process.channel` - -* {number} - -Gets the amount of free memory that is still available to the process -(in bytes). - -See [`uv_get_available_memory`][uv_get_available_memory] for more -information. - ## `process.cpuUsage([previousValue])` + +> Stability: 1 - Experimental + +* `file` {string} The name or path of the executable file to run. +* `args` {string\[]} List of string arguments. No argument can contain a null-byte (`\u0000`). +* `env` {Object} Environment key-value pairs. + No key or value can contain a null-byte (`\u0000`). + **Default:** `process.env`. + +Replaces the current process with a new process. + +This is achieved by using the `execve` POSIX function and therefore no memory or other +resources from the current process are preserved, except for the standard input, +standard output and standard error file descriptor. + +All other resources are discarded by the system when the processes are swapped, without triggering +any exit or close events and without running any cleanup handler. + +This function will never return, unless an error occurred. + +This function is not available on Windows or IBM i. + ## `process.exit([code])` - -> Stability: 1 - Experimental - -* `file` {string} The name or path of the executable file to run. -* `args` {string\[]} List of string arguments. No argument can contain a null-byte (`\u0000`). -* `env` {Object} Environment key-value pairs. - No key or value can contain a null-byte (`\u0000`). - **Default:** `process.env`. - -Replaces the current process with a new process. - -This is achieved by using the `execve` POSIX function and therefore no memory or other -resources from the current process are preserved, except for the standard input, -standard output and standard error file descriptor. - -All other resources are discarded by the system when the processes are swapped, without triggering -any exit or close events and without running any cleanup handler. - -This function will never return, unless an error occurred. - -This function is not available on Windows or IBM i. - ## `process.report` -> Stability: 1 - Experimental - ### Class: `readlinePromises.Interface` -> Stability: 1 - Experimental - * {boolean} Returns whether the stream was destroyed or errored before emitting `'finish'`. @@ -1635,10 +1637,12 @@ the stream has not been destroyed or emitted `'error'` or `'end'`. -> Stability: 1 - Experimental - * {boolean} Returns whether the stream was destroyed or errored before emitting `'end'`. @@ -1649,10 +1653,12 @@ Returns whether the stream was destroyed or errored before emitting `'end'`. added: - v16.7.0 - v14.18.0 +changes: + - version: v22.17.0 + pr-url: https://github.com/nodejs/node/pull/57513 + description: Marking the API stable. --> -> Stability: 1 - Experimental - * {boolean} Returns whether `'data'` has been emitted. @@ -1995,10 +2001,12 @@ a promise that fulfills when the stream is finished. added: - v19.1.0 - v18.13.0 +changes: + - version: v22.17.0 + pr-url: https://github.com/nodejs/node/pull/57513 + description: Marking the API stable. --> -> Stability: 1 - Experimental - * `stream` {Stream|Iterable|AsyncIterable|Function} * `options` {Object} * `signal` {AbortSignal} allows destroying the stream if the signal is @@ -2030,10 +2038,12 @@ See [`stream.compose`][] for more information. -> Stability: 1 - Experimental - * `options` {Object} * `destroyOnReturn` {boolean} When set to `false`, calling `return` on the async iterator, or exiting a `for await...of` iteration using a `break`, @@ -3069,10 +3079,12 @@ Readable.from([ -> Stability: 1 - Experimental - * `readableStream` {ReadableStream} * `options` {Object} * `encoding` {string} @@ -3085,10 +3097,12 @@ added: v17.0.0 -> Stability: 1 - Experimental - * `stream` {stream.Readable|ReadableStream} * Returns: `boolean` @@ -3100,10 +3114,12 @@ Returns whether the stream has been read from or cancelled. added: - v17.3.0 - v16.14.0 +changes: + - version: v22.17.0 + pr-url: https://github.com/nodejs/node/pull/57513 + description: Marking the API stable. --> -> Stability: 1 - Experimental - * `stream` {Readable|Writable|Duplex|WritableStream|ReadableStream} * Returns: {boolean} @@ -3115,10 +3131,12 @@ Returns whether the stream has encountered an error. added: - v17.4.0 - v16.14.0 +changes: + - version: v22.17.0 + pr-url: https://github.com/nodejs/node/pull/57513 + description: Marking the API stable. --> -> Stability: 1 - Experimental - * `stream` {Readable|Duplex|ReadableStream} * Returns: {boolean} @@ -3129,14 +3147,15 @@ Returns whether the stream is readable. -> Stability: 1 - Experimental - * `streamReadable` {stream.Readable} * `options` {Object} * `strategy` {Object} @@ -3154,10 +3173,12 @@ changes: -> Stability: 1 - Experimental - * `writableStream` {WritableStream} * `options` {Object} * `decodeStrings` {boolean} @@ -3170,10 +3191,12 @@ added: v17.0.0 -> Stability: 1 - Experimental - * `streamWritable` {stream.Writable} * Returns: {WritableStream} @@ -3232,10 +3255,12 @@ Duplex.from([ -> Stability: 1 - Experimental - * `pair` {Object} * `readable` {ReadableStream} * `writable` {WritableStream} @@ -3313,10 +3338,12 @@ duplex.once('readable', () => console.log('readable', duplex.read())); -> Stability: 1 - Experimental - * `streamDuplex` {stream.Duplex} * Returns: {Object} * `readable` {ReadableStream} diff --git a/doc/api/test.md b/doc/api/test.md index a9703998c5cf25..81b306d2f2f97f 100644 --- a/doc/api/test.md +++ b/doc/api/test.md @@ -935,7 +935,7 @@ added: v22.3.0 changes: - version: v23.4.0 pr-url: https://github.com/nodejs/node/pull/55897 - description: Snapsnot testing is no longer experimental. + description: Snapshot testing is no longer experimental. --> Snapshot tests allow arbitrary values to be serialized into string values and @@ -2108,6 +2108,11 @@ test('spies on an object method', (t) => { > Stability: 1.0 - Early development @@ -2131,10 +2136,10 @@ added: v22.3.0 mock will throw an exception when used as a CJS or builtin module. * Returns: {MockModuleContext} An object that can be used to manipulate the mock. -This function is used to mock the exports of ECMAScript modules, CommonJS -modules, and Node.js builtin modules. Any references to the original module -prior to mocking are not impacted. In order to enable module mocking, Node.js must -be started with the [`--experimental-test-module-mocks`][] command-line flag. +This function is used to mock the exports of ECMAScript modules, CommonJS modules, JSON modules, and +Node.js builtin modules. Any references to the original module prior to mocking are not impacted. In +order to enable module mocking, Node.js must be started with the +[`--experimental-test-module-mocks`][] command-line flag. The following example demonstrates how a mock is created for a module. @@ -2942,6 +2947,11 @@ defined. The corresponding declaration ordered event is `'test:start'`. `undefined` if the test was run through the REPL. * `message` {string} The diagnostic message. * `nesting` {number} The nesting level of the test. + * `level` {string} The severity level of the diagnostic message. + Possible values are: + * `'info'`: Informational messages. + * `'warn'`: Warnings. + * `'error'`: Errors. Emitted when [`context.diagnostic`][] is called. This event is guaranteed to be emitted in the same order as the tests are diff --git a/doc/api/url.md b/doc/api/url.md index b8577381aa47ea..487ad9ac452ca4 100644 --- a/doc/api/url.md +++ b/doc/api/url.md @@ -628,10 +628,12 @@ console.log(JSON.stringify(myURLs)); -> Stability: 1 - Experimental - * `blob` {Blob} * Returns: {string} @@ -664,10 +666,12 @@ to other workers or the main thread. -> Stability: 1 - Experimental - * `id` {string} A `'blob:nodedata:...` URL string returned by a prior call to `URL.createObjectURL()`. @@ -913,7 +917,7 @@ Returns an ES6 `Iterator` over each of the name-value pairs in the query. Each item of the iterator is a JavaScript `Array`. The first item of the `Array` is the `name`, the second item of the `Array` is the `value`. -Alias for [`urlSearchParams[@@iterator]()`][`urlSearchParams@@iterator()`]. +Alias for [`urlSearchParams[Symbol.iterator]()`][`urlSearchParamsSymbol.iterator()`]. #### `urlSearchParams.forEach(fn[, thisArg])` @@ -1834,7 +1838,7 @@ console.log(myURL.origin); [`url.toJSON()`]: #urltojson [`url.toString()`]: #urltostring [`urlSearchParams.entries()`]: #urlsearchparamsentries -[`urlSearchParams@@iterator()`]: #urlsearchparamssymboliterator +[`urlSearchParamsSymbol.iterator()`]: #urlsearchparamssymboliterator [converted to a string]: https://tc39.es/ecma262/#sec-tostring [examples of parsed URLs]: https://url.spec.whatwg.org/#example-url-parsing [host name spoofing]: https://hackerone.com/reports/678487 diff --git a/doc/api/util.md b/doc/api/util.md index 3b0fd5a5844107..979b5e9e81f1e9 100644 --- a/doc/api/util.md +++ b/doc/api/util.md @@ -963,8 +963,8 @@ The `util.inspect()` method returns a string representation of `object` that is intended for debugging. The output of `util.inspect` may change at any time and should not be depended upon programmatically. Additional `options` may be passed that alter the result. -`util.inspect()` will use the constructor's name and/or `@@toStringTag` to make -an identifiable tag for an inspected value. +`util.inspect()` will use the constructor's name and/or `Symbol.toStringTag` +property to make an identifiable tag for an inspected value. ```js class Foo { @@ -1872,7 +1872,7 @@ console.log(params.toString()); Returns an iterator over the values of each name-value pair. -### `mimeParams[@@iterator]()` +### `mimeParams[Symbol.iterator]()` * Returns: {Iterator} @@ -2394,6 +2394,9 @@ added: - v21.7.0 - v20.12.0 changes: + - version: v22.17.0 + pr-url: https://github.com/nodejs/node/pull/58437 + description: Added the `'none'` format as a non-op format. - version: v22.13.0 pr-url: https://github.com/nodejs/node/pull/56265 description: styleText is now stable. @@ -2467,6 +2470,8 @@ console.log( ); ``` +The special format value `none` applies no additional styling to the text. + The full list of formats can be found in [modifiers][]. ## Class: `util.TextDecoder` diff --git a/doc/api/v8.md b/doc/api/v8.md index d949b12ca49050..6ce4c5bc52a114 100644 --- a/doc/api/v8.md +++ b/doc/api/v8.md @@ -578,10 +578,12 @@ if (isMainThread) { added: - v18.10.0 - v16.18.0 +changes: + - version: v22.17.0 + pr-url: https://github.com/nodejs/node/pull/57513 + description: Marking the API stable. --> -> Stability: 1 - Experimental - * `limit` {integer} The API is a no-op if `--heapsnapshot-near-heap-limit` is already set from the @@ -1114,10 +1116,12 @@ occur synchronously in the case of `Promise.resolve()` or `Promise.reject()`. added: - v18.6.0 - v16.17.0 +changes: + - version: v22.17.0 + pr-url: https://github.com/nodejs/node/pull/57513 + description: Marking the API stable. --> -> Stability: 1 - Experimental - The `v8.startupSnapshot` interface can be used to add serialization and deserialization hooks for custom startup snapshots. diff --git a/doc/api/webcrypto.md b/doc/api/webcrypto.md index 78332585402ce6..0bf068bcd8157f 100644 --- a/doc/api/webcrypto.md +++ b/doc/api/webcrypto.md @@ -439,7 +439,7 @@ added: v15.0.0 -* Type: {AesKeyGenParams|RsaHashedKeyGenParams|EcKeyGenParams|HmacKeyGenParams} +* Type: {KeyAlgorithm|RsaHashedKeyAlgorithm|EcKeyAlgorithm|AesKeyAlgorithm|HmacKeyAlgorithm} @@ -630,7 +630,7 @@ changes: * `algorithm`: {EcdhKeyDeriveParams|HkdfParams|Pbkdf2Params} * `baseKey`: {CryptoKey} -* `derivedKeyAlgorithm`: {string|AlgorithmIdentifier|HmacImportParams|AesDerivedKeyParams} +* `derivedKeyAlgorithm`: {string|Algorithm|HmacImportParams|AesDerivedKeyParams} * `extractable`: {boolean} * `keyUsages`: {string\[]} See [Key usages][]. * Returns: {Promise} Fulfills with a {CryptoKey} upon success. @@ -660,7 +660,7 @@ The algorithms currently supported include: added: v15.0.0 --> -* `algorithm`: {string|AlgorithmIdentifier} +* `algorithm`: {string|Algorithm} * `data`: {ArrayBuffer|TypedArray|DataView|Buffer} * Returns: {Promise} Fulfills with an {ArrayBuffer} upon success. @@ -756,7 +756,7 @@ added: v15.0.0 -* `algorithm`: {string|AlgorithmIdentifier|RsaHashedKeyGenParams|EcKeyGenParams|HmacKeyGenParams|AesKeyGenParams} +* `algorithm`: {string|Algorithm|RsaHashedKeyGenParams|EcKeyGenParams|HmacKeyGenParams|AesKeyGenParams} @@ -810,7 +810,7 @@ changes: -* `algorithm`: {string|AlgorithmIdentifier|RsaHashedImportParams|EcKeyImportParams|HmacImportParams} +* `algorithm`: {string|Algorithm|RsaHashedImportParams|EcKeyImportParams|HmacImportParams} @@ -860,7 +860,7 @@ changes: -* `algorithm`: {string|AlgorithmIdentifier|RsaPssParams|EcdsaParams|Ed448Params} +* `algorithm`: {string|Algorithm|RsaPssParams|EcdsaParams|Ed448Params} * `key`: {CryptoKey} * `data`: {ArrayBuffer|TypedArray|DataView|Buffer} * Returns: {Promise} Fulfills with an {ArrayBuffer} upon success. @@ -893,8 +893,8 @@ added: v15.0.0 -* `unwrapAlgo`: {string|AlgorithmIdentifier|RsaOaepParams|AesCtrParams|AesCbcParams|AesGcmParams} -* `unwrappedKeyAlgo`: {string|AlgorithmIdentifier|RsaHashedImportParams|EcKeyImportParams|HmacImportParams} +* `unwrapAlgo`: {string|Algorithm|RsaOaepParams|AesCtrParams|AesCbcParams|AesGcmParams} +* `unwrappedKeyAlgo`: {string|Algorithm|RsaHashedImportParams|EcKeyImportParams|HmacImportParams} @@ -950,7 +950,7 @@ changes: -* `algorithm`: {string|AlgorithmIdentifier|RsaPssParams|EcdsaParams|Ed448Params} +* `algorithm`: {string|Algorithm|RsaPssParams|EcdsaParams|Ed448Params} * `key`: {CryptoKey} * `signature`: {ArrayBuffer|TypedArray|DataView|Buffer} * `data`: {ArrayBuffer|TypedArray|DataView|Buffer} @@ -983,7 +983,7 @@ added: v15.0.0 * `format`: {string} Must be one of `'raw'`, `'pkcs8'`, `'spki'`, or `'jwk'`. * `key`: {CryptoKey} * `wrappingKey`: {CryptoKey} -* `wrapAlgo`: {string|AlgorithmIdentifier|RsaOaepParams|AesCtrParams|AesCbcParams|AesGcmParams} +* `wrapAlgo`: {string|Algorithm|RsaOaepParams|AesCtrParams|AesCbcParams|AesGcmParams} * Returns: {Promise} Fulfills with an {ArrayBuffer} upon success. @@ -1012,13 +1012,13 @@ The algorithm parameter objects define the methods and parameters used by the various {SubtleCrypto} methods. While described here as "classes", they are simple JavaScript dictionary objects. -### Class: `AlgorithmIdentifier` +### Class: `Algorithm` -#### `algorithmIdentifier.name` +#### `Algorithm.name` + +#### `aesKeyAlgorithm.length` + + + +* Type: {number} + +The length of the AES key in bits. + +#### `aesKeyAlgorithm.name` + + + +* Type: {string} + ### Class: `AesKeyGenParams` -* Type: {string|Object} +* Type: {string|Algorithm} If represented as a {string}, the value must be one of: @@ -1240,8 +1264,8 @@ If represented as a {string}, the value must be one of: * `'SHA-384'` * `'SHA-512'` -If represented as an {Object}, the object must have a `name` property -whose value is one of the above listed values. +If represented as an {Algorithm}, the object's `name` property +must be one of the above listed values. #### `ecdsaParams.name` @@ -1251,6 +1275,28 @@ added: v15.0.0 * Type: {string} Must be `'ECDSA'`. +### Class: `EcKeyAlgorithm` + + + +#### `ecKeyAlgorithm.name` + + + +* Type: {string} + +#### `ecKeyAlgorithm.namedCurve` + + + +* Type: {string} + ### Class: `EcKeyGenParams` -* Type: {string|Object} +* Type: {string|Algorithm} If represented as a {string}, the value must be one of: @@ -1347,8 +1393,8 @@ If represented as a {string}, the value must be one of: * `'SHA-384'` * `'SHA-512'` -If represented as an {Object}, the object must have a `name` property -whose value is one of the above listed values. +If represented as an {Algorithm}, the object's `name` property +must be one of the above listed values. #### `hkdfParams.info` @@ -1394,7 +1440,7 @@ added: v15.0.0 added: v15.0.0 --> -* Type: {string|Object} +* Type: {string|Algorithm} If represented as a {string}, the value must be one of: @@ -1403,8 +1449,8 @@ If represented as a {string}, the value must be one of: * `'SHA-384'` * `'SHA-512'` -If represented as an {Object}, the object must have a `name` property -whose value is one of the above listed values. +If represented as an {Algorithm}, the object's `name` property +must be one of the above listed values. #### `hmacImportParams.length` @@ -1425,6 +1471,38 @@ added: v15.0.0 * Type: {string} Must be `'HMAC'`. +### Class: `HmacKeyAlgorithm` + + + +#### `hmacKeyAlgorithm.hash` + + + +* Type: {Algorithm} + +#### `hmacKeyAlgorithm.length` + + + +* Type: {number} + +The length of the HMAC key in bits. + +#### `hmacKeyAlgorithm.name` + + + +* Type: {string} + ### Class: `HmacKeyGenParams` -* Type: {string|Object} +* Type: {string|Algorithm} If represented as a {string}, the value must be one of: @@ -1446,8 +1524,8 @@ If represented as a {string}, the value must be one of: * `'SHA-384'` * `'SHA-512'` -If represented as an {Object}, the object must have a `name` property -whose value is one of the above listed values. +If represented as an {Algorithm}, the object's `name` property +must be one of the above listed values. #### `hmacKeyGenParams.length` @@ -1469,6 +1547,20 @@ added: v15.0.0 * Type: {string} Must be `'HMAC'`. +### Class: `KeyAlgorithm` + + + +#### `keyAlgorithm.name` + + + +* Type: {string} + ### Class: `Pbkdf2Params` -* Type: {string|Object} +* Type: {string|Algorithm} If represented as a {string}, the value must be one of: @@ -1490,8 +1582,8 @@ If represented as a {string}, the value must be one of: * `'SHA-384'` * `'SHA-512'` -If represented as an {Object}, the object must have a `name` property -whose value is one of the above listed values. +If represented as an {Algorithm}, the object's `name` property +must be one of the above listed values. #### `pbkdf2Params.iterations` @@ -1533,7 +1625,7 @@ added: v15.0.0 added: v15.0.0 --> -* Type: {string|Object} +* Type: {string|Algorithm} If represented as a {string}, the value must be one of: @@ -1542,8 +1634,8 @@ If represented as a {string}, the value must be one of: * `'SHA-384'` * `'SHA-512'` -If represented as an {Object}, the object must have a `name` property -whose value is one of the above listed values. +If represented as an {Algorithm}, the object's `name` property +must be one of the above listed values. #### `rsaHashedImportParams.name` @@ -1554,6 +1646,48 @@ added: v15.0.0 * Type: {string} Must be one of `'RSASSA-PKCS1-v1_5'`, `'RSA-PSS'`, or `'RSA-OAEP'`. +### Class: `RsaHashedKeyAlgorithm` + + + +#### `rsaHashedKeyAlgorithm.hash` + + + +* Type: {Algorithm} + +#### `rsaHashedKeyAlgorithm.modulusLength` + + + +* Type: {number} + +The length in bits of the RSA modulus. + +#### `rsaHashedKeyAlgorithm.name` + + + +* Type: {string} + +#### `rsaHashedKeyAlgorithm.publicExponent` + + + +* Type: {Uint8Array} + +The RSA public exponent. + ### Class: `RsaHashedKeyGenParams` -* Type: {string|Object} +* Type: {string|Algorithm} If represented as a {string}, the value must be one of: @@ -1575,8 +1709,8 @@ If represented as a {string}, the value must be one of: * `'SHA-384'` * `'SHA-512'` -If represented as an {Object}, the object must have a `name` property -whose value is one of the above listed values. +If represented as an {Algorithm}, the object's `name` property +must be one of the above listed values. #### `rsaHashedKeyGenParams.modulusLength` diff --git a/doc/api/worker_threads.md b/doc/api/worker_threads.md index 38ad4771bf81ea..06b9d488eaff4d 100644 --- a/doc/api/worker_threads.md +++ b/doc/api/worker_threads.md @@ -1267,10 +1267,12 @@ port2.postMessage(new URL('https://example.org')); added: - v18.1.0 - v16.17.0 +changes: + - version: v22.17.0 + pr-url: https://github.com/nodejs/node/pull/57513 + description: Marking the API stable. --> -> Stability: 1 - Experimental - * Returns: {boolean} If true, the `MessagePort` object will keep the Node.js event loop active. diff --git a/doc/api/zlib.md b/doc/api/zlib.md index a7e69bfb6f8bce..ded1e96d474bc9 100644 --- a/doc/api/zlib.md +++ b/doc/api/zlib.md @@ -615,7 +615,6 @@ Allowed flush values. * `zlib.constants.Z_FULL_FLUSH` * `zlib.constants.Z_FINISH` * `zlib.constants.Z_BLOCK` -* `zlib.constants.Z_TREES` Return codes for the compression/decompression functions. Negative values are errors, positive values are used for special but normal @@ -832,6 +831,7 @@ Each Brotli-based class takes an `options` object. All options are optional. * `params` {Object} Key-value object containing indexed [Brotli parameters][]. * `maxOutputLength` {integer} Limits output size when using [convenience methods][]. **Default:** [`buffer.kMaxLength`][] +* `info` {boolean} If `true`, returns an object with `buffer` and `engine`. **Default:** `false` For example: @@ -854,6 +854,8 @@ added: - v10.16.0 --> +* Extends: [`ZlibBase`][] + Compress data using the Brotli algorithm. ## Class: `zlib.BrotliDecompress` @@ -864,6 +866,8 @@ added: - v10.16.0 --> +* Extends: [`ZlibBase`][] + Decompress data using the Brotli algorithm. ## Class: `zlib.Deflate` @@ -872,6 +876,8 @@ Decompress data using the Brotli algorithm. added: v0.5.8 --> +* Extends: [`ZlibBase`][] + Compress data using deflate. ## Class: `zlib.DeflateRaw` @@ -880,6 +886,8 @@ Compress data using deflate. added: v0.5.8 --> +* Extends: [`ZlibBase`][] + Compress data using deflate, and do not append a `zlib` header. ## Class: `zlib.Gunzip` @@ -899,6 +907,8 @@ changes: description: A truncated input stream will now result in an `'error'` event. --> +* Extends: [`ZlibBase`][] + Decompress a gzip stream. ## Class: `zlib.Gzip` @@ -907,6 +917,8 @@ Decompress a gzip stream. added: v0.5.8 --> +* Extends: [`ZlibBase`][] + Compress data using gzip. ## Class: `zlib.Inflate` @@ -919,6 +931,8 @@ changes: description: A truncated input stream will now result in an `'error'` event. --> +* Extends: [`ZlibBase`][] + Decompress a deflate stream. ## Class: `zlib.InflateRaw` @@ -934,6 +948,8 @@ changes: description: A truncated input stream will now result in an `'error'` event. --> +* Extends: [`ZlibBase`][] + Decompress a raw deflate stream. ## Class: `zlib.Unzip` @@ -942,6 +958,8 @@ Decompress a raw deflate stream. added: v0.5.8 --> +* Extends: [`ZlibBase`][] + Decompress either a Gzip- or Deflate-compressed stream by auto-detecting the header. @@ -957,6 +975,8 @@ changes: description: This class was renamed from `Zlib` to `ZlibBase`. --> +* Extends: [`stream.Transform`][] + Not exported by the `node:zlib` module. It is documented here because it is the base class of the compressor/decompressor classes. @@ -1061,6 +1081,7 @@ Each Zstd-based class takes an `options` object. All options are optional. * `params` {Object} Key-value object containing indexed [Zstd parameters][]. * `maxOutputLength` {integer} Limits output size when using [convenience methods][]. **Default:** [`buffer.kMaxLength`][] +* `info` {boolean} If `true`, returns an object with `buffer` and `engine`. **Default:** `false` For example: @@ -1701,6 +1722,7 @@ Decompress a chunk of data with [`ZstdDecompress`][]. [`InflateRaw`]: #class-zlibinflateraw [`Inflate`]: #class-zlibinflate [`Unzip`]: #class-zlibunzip +[`ZlibBase`]: #class-zlibzlibbase [`ZstdCompress`]: #class-zlibzstdcompress [`ZstdDecompress`]: #class-zlibzstddecompress [`buffer.kMaxLength`]: buffer.md#bufferkmaxlength diff --git a/doc/api_assets/style.css b/doc/api_assets/style.css index b9af9ddea55aca..c23e486ef80b82 100644 --- a/doc/api_assets/style.css +++ b/doc/api_assets/style.css @@ -299,6 +299,10 @@ li.picker-header a span { z-index: 1; } +#api-section-documentation .api_stability { + position: static; +} + .api_stability * { color: var(--white) !important; } diff --git a/doc/changelogs/CHANGELOG_V22.md b/doc/changelogs/CHANGELOG_V22.md index df4813a5accd02..6205d3dcf14818 100644 --- a/doc/changelogs/CHANGELOG_V22.md +++ b/doc/changelogs/CHANGELOG_V22.md @@ -9,6 +9,7 @@ +22.17.0
    22.16.0
    22.15.1
    22.15.0
    @@ -60,6 +61,310 @@ * [io.js](CHANGELOG_IOJS.md) * [Archive](CHANGELOG_ARCHIVE.md) + + +## 2025-06-24, Version 22.17.0 'Jod' (LTS), @aduh95 + +### Notable Changes + +#### ⚠️ Deprecations + +##### Instantiating `node:http` classes **without `new`** + +Constructing classes like `IncomingMessage` or `ServerResponse` without the `new` +keyword is now discouraged. This clarifies API expectations and aligns with standard +JavaScript behavior. It may warn or error in future versions. + +Contributed by Yagiz Nizipli in [#58518](https://github.com/nodejs/node/pull/58518). + +##### `options.shell = ""` in `node:child_process` + +Using an empty string for `shell` previously had undefined behavior. This change +encourages explicit choices (e.g., `shell: true` or a shell path) and avoids +relying on implementation quirks. + +Contributed by Antoine du Hamel and Renegade334 [#58564](https://github.com/nodejs/node/pull/58564). + +##### HTTP/2 priority signaling + +The HTTP/2 prioritization API (e.g., `stream.priority`) is now deprecated due to +poor real-world support. Applications should avoid using priority hints and expect future removal. + +Contributed by Matteo Collina and Antoine du Hamel [#58313](https://github.com/nodejs/node/pull/58313). + +#### ✅ Features graduated to stable + +##### `assert.partialDeepStrictEqual()` + +This method compares only a subset of properties in deep object comparisons, +useful for flexible test assertions. Its stabilization means it's now safe for +general use and won't change unexpectedly in future releases. + +Contributed by Ruben Bridgewater in [#57370](https://github.com/nodejs/node/pull/57370). + +#### Miscellaneous + +* `dirent.parentPath` +* `filehandle.readableWebStream()` +* `fs.glob()` +* `fs.openAsBlob()` +* `node:readline/promises` +* `port.hasRef()` +* `readable.compose()` +* `readable.iterator()` +* `readable.readableAborted` +* `readable.readableDidRead` +* `Duplex.fromWeb()` +* `Duplex.toWeb()` +* `Readable.fromWeb()` +* `Readable.isDisturbed()` +* `Readable.toWeb()` +* `stream.isErrored()` +* `stream.isReadable()` +* `URL.createObjectURL()` +* `URL.revokeObjectURL()` +* `v8.setHeapSnapshotNearHeapLimit()` +* `Writable.fromWeb()` +* `Writable.toWeb()` +* `writable.writableAborted` +* Startup Snapshot API +* `ERR_INPUT_TYPE_NOT_ALLOWED` +* `ERR_UNKNOWN_FILE_EXTENSION` +* `ERR_UNKNOWN_MODULE_FORMAT` +* `ERR_USE_AFTER_CLOSE` + +Contributed by James M Snell in +[#57513](https://github.com/nodejs/node/pull/57513) and +[#58541](https://github.com/nodejs/node/pull/58541). + +#### Semver-minor features + +##### 🔧 `fs.FileHandle.readableWebStream` gets `autoClose` option + +This gives developers explicit control over whether the file descriptor should +be closed when the stream ends. Helps avoid subtle resource leaks. + +Contributed by James M Snell in [#58548](https://github.com/nodejs/node/pull/58548). + +##### 🔧 `fs.Dir` now supports **explicit resource management** + +This improves ergonomics around async iteration of directories. Developers can +now manually control when a directory is closed using `.close()` or with `Symbol.asyncDispose`. + +Contributed by Antoine du Hamel in [#58206](https://github.com/nodejs/node/pull/58206). + +##### 📊 `http2` gains diagnostics channel: `http2.server.stream.finish` + +Adds observability support for when a stream finishes. Useful for logging, +monitoring, and debugging HTTP/2 behavior without patching internals. + +Contributed by Darshan Sen in [#58560](https://github.com/nodejs/node/pull/58560). + +##### 🔐 Permissions: implicit allow-fs-read to entrypoint + +Node.js permissions model now allows read access to the entry file by default. +It makes running permission-restricted apps smoother while preserving security. + +Contributed by Rafael Gonzaga in [#58579](https://github.com/nodejs/node/pull/58579). + +##### 🎨 `util.styleText()` adds `'none'` style + +This lets developers remove styling cleanly without hacks. Useful for overriding +inherited terminal styles when composing styled strings. + +Contributed by James M Snell in [#58437](https://github.com/nodejs/node/pull/58437). + +#### 🧑‍💻 Community updates + +* \[[`0105c13556`](https://github.com/nodejs/node/commit/0105c13556)] - **doc**: add Filip Skokan to TSC (Rafael Gonzaga) [#58499](https://github.com/nodejs/node/pull/58499) +* \[[`3b857735ef`](https://github.com/nodejs/node/commit/3b857735ef)] - **doc**: add JonasBa to collaborators (Jonas Badalic) [#58355](https://github.com/nodejs/node/pull/58355) +* \[[`fdf7612735`](https://github.com/nodejs/node/commit/fdf7612735)] - **doc**: add puskin to collaborators (Giovanni Bucci) [#58308](https://github.com/nodejs/node/pull/58308) + +### Commits + +* \[[`ffe7e1ace0`](https://github.com/nodejs/node/commit/ffe7e1ace0)] - **(SEMVER-MINOR)** **assert**: mark partialDeepStrictEqual() as stable (Ruben Bridgewater) [#57370](https://github.com/nodejs/node/pull/57370) +* \[[`269931f289`](https://github.com/nodejs/node/commit/269931f289)] - **async\_hooks**: ensure AsyncLocalStore instances work isolated (Gerhard Stöbich) [#58149](https://github.com/nodejs/node/pull/58149) +* \[[`9e0746a4ff`](https://github.com/nodejs/node/commit/9e0746a4ff)] - **benchmark**: fix broken fs.cpSync benchmark (Dario Piotrowicz) [#58472](https://github.com/nodejs/node/pull/58472) +* \[[`dee8cb5bcb`](https://github.com/nodejs/node/commit/dee8cb5bcb)] - **benchmark**: add more options to cp-sync (Sonny) [#58278](https://github.com/nodejs/node/pull/58278) +* \[[`e840fd5b85`](https://github.com/nodejs/node/commit/e840fd5b85)] - **benchmark**: fix typo in method name for error-stack (Miguel Marcondes Filho) [#58128](https://github.com/nodejs/node/pull/58128) +* \[[`b9a16e97e0`](https://github.com/nodejs/node/commit/b9a16e97e0)] - **buffer**: give names to `Buffer.prototype.*Write()` functions (Livia Medeiros) [#58258](https://github.com/nodejs/node/pull/58258) +* \[[`d56a5e40af`](https://github.com/nodejs/node/commit/d56a5e40af)] - **buffer**: use constexpr where possible (Yagiz Nizipli) [#58141](https://github.com/nodejs/node/pull/58141) +* \[[`215587feca`](https://github.com/nodejs/node/commit/215587feca)] - **build**: add support for OpenHarmony operating system (hqzing) [#58350](https://github.com/nodejs/node/pull/58350) +* \[[`9bcef6821c`](https://github.com/nodejs/node/commit/9bcef6821c)] - **build**: fix uvwasi pkgname (Antoine du Hamel) [#58270](https://github.com/nodejs/node/pull/58270) +* \[[`7c3883c2ae`](https://github.com/nodejs/node/commit/7c3883c2ae)] - **build**: search for libnode.so in multiple places (Jan Staněk) [#58213](https://github.com/nodejs/node/pull/58213) +* \[[`3f954accb3`](https://github.com/nodejs/node/commit/3f954accb3)] - **build**: fix pointer compression builds (Joyee Cheung) [#58171](https://github.com/nodejs/node/pull/58171) +* \[[`04c8f59f84`](https://github.com/nodejs/node/commit/04c8f59f84)] - **build**: use FILE\_OFFSET\_BITS=64 esp. on 32-bit arch (RafaelGSS) [#58090](https://github.com/nodejs/node/pull/58090) +* \[[`8c2cf3a372`](https://github.com/nodejs/node/commit/8c2cf3a372)] - **build**: use //third\_party/simdutf by default in GN (Shelley Vohr) [#58115](https://github.com/nodejs/node/pull/58115) +* \[[`cff8006792`](https://github.com/nodejs/node/commit/cff8006792)] - **child\_process**: give names to `ChildProcess` functions (Livia Medeiros) [#58370](https://github.com/nodejs/node/pull/58370) +* \[[`6816d779b6`](https://github.com/nodejs/node/commit/6816d779b6)] - **child\_process**: give names to promisified `exec()` and `execFile()` (LiviaMedeiros) [#57916](https://github.com/nodejs/node/pull/57916) +* \[[`5572cecca4`](https://github.com/nodejs/node/commit/5572cecca4)] - **crypto**: expose crypto.constants.OPENSSL\_IS\_BORINGSSL (Shelley Vohr) [#58387](https://github.com/nodejs/node/pull/58387) +* \[[`d6aa02889c`](https://github.com/nodejs/node/commit/d6aa02889c)] - **deps**: use proper C standard when building libuv (Yaksh Bariya) [#58587](https://github.com/nodejs/node/pull/58587) +* \[[`375a6413d5`](https://github.com/nodejs/node/commit/375a6413d5)] - **deps**: update simdjson to 3.12.3 (Node.js GitHub Bot) [#57682](https://github.com/nodejs/node/pull/57682) +* \[[`e0cd138e52`](https://github.com/nodejs/node/commit/e0cd138e52)] - **deps**: update googletest to e9092b1 (Node.js GitHub Bot) [#58565](https://github.com/nodejs/node/pull/58565) +* \[[`31e592631f`](https://github.com/nodejs/node/commit/31e592631f)] - **deps**: update corepack to 0.33.0 (Node.js GitHub Bot) [#58566](https://github.com/nodejs/node/pull/58566) +* \[[`386c24260b`](https://github.com/nodejs/node/commit/386c24260b)] - **deps**: update sqlite to 3.50.0 (Node.js GitHub Bot) [#58272](https://github.com/nodejs/node/pull/58272) +* \[[`f84998d40b`](https://github.com/nodejs/node/commit/f84998d40b)] - **deps**: update OpenSSL gen container to Ubuntu 22.04 (Michaël Zasso) [#58432](https://github.com/nodejs/node/pull/58432) +* \[[`d49fd29859`](https://github.com/nodejs/node/commit/d49fd29859)] - **deps**: update llhttp to 9.3.0 (Fedor Indutny) [#58144](https://github.com/nodejs/node/pull/58144) +* \[[`e397980a1a`](https://github.com/nodejs/node/commit/e397980a1a)] - **deps**: update libuv to 1.51.0 (Node.js GitHub Bot) [#58124](https://github.com/nodejs/node/pull/58124) +* \[[`a28c33645c`](https://github.com/nodejs/node/commit/a28c33645c)] - **dns**: fix dns query cache implementation (Ethan Arrowood) [#58404](https://github.com/nodejs/node/pull/58404) +* \[[`6939b0c624`](https://github.com/nodejs/node/commit/6939b0c624)] - **doc**: fix the order of `process.md` sections (Allon Murienik) [#58403](https://github.com/nodejs/node/pull/58403) +* \[[`1ca253c363`](https://github.com/nodejs/node/commit/1ca253c363)] - **doc**: add support link for panva (Filip Skokan) [#58591](https://github.com/nodejs/node/pull/58591) +* \[[`8319edbcf6`](https://github.com/nodejs/node/commit/8319edbcf6)] - **doc**: update metadata for \_transformState deprecation (James M Snell) [#58530](https://github.com/nodejs/node/pull/58530) +* \[[`697d258136`](https://github.com/nodejs/node/commit/697d258136)] - **doc**: deprecate passing an empty string to `options.shell` (Antoine du Hamel) [#58564](https://github.com/nodejs/node/pull/58564) +* \[[`132fc804e8`](https://github.com/nodejs/node/commit/132fc804e8)] - **doc**: correct formatting of example definitions for `--test-shard` (Jacob Smith) [#58571](https://github.com/nodejs/node/pull/58571) +* \[[`7d0df646f6`](https://github.com/nodejs/node/commit/7d0df646f6)] - **doc**: clarify DEP0194 scope (Antoine du Hamel) [#58504](https://github.com/nodejs/node/pull/58504) +* \[[`1e6d7da0ce`](https://github.com/nodejs/node/commit/1e6d7da0ce)] - **doc**: deprecate HTTP/2 priority signaling (Matteo Collina) [#58313](https://github.com/nodejs/node/pull/58313) +* \[[`5a917bc1d0`](https://github.com/nodejs/node/commit/5a917bc1d0)] - **doc**: explain child\_process code and signal null values everywhere (Darshan Sen) [#58479](https://github.com/nodejs/node/pull/58479) +* \[[`0105c13556`](https://github.com/nodejs/node/commit/0105c13556)] - **doc**: add Filip Skokan to TSC (Rafael Gonzaga) [#58499](https://github.com/nodejs/node/pull/58499) +* \[[`2bdc87cd64`](https://github.com/nodejs/node/commit/2bdc87cd64)] - **doc**: update `git node release` example (Antoine du Hamel) [#58475](https://github.com/nodejs/node/pull/58475) +* \[[`28f9b43186`](https://github.com/nodejs/node/commit/28f9b43186)] - **doc**: add missing options.info for ZstdOptions (Jimmy Leung) [#58360](https://github.com/nodejs/node/pull/58360) +* \[[`e19496dfc1`](https://github.com/nodejs/node/commit/e19496dfc1)] - **doc**: add missing options.info for BrotliOptions (Jimmy Leung) [#58359](https://github.com/nodejs/node/pull/58359) +* \[[`7f905863db`](https://github.com/nodejs/node/commit/7f905863db)] - **doc**: clarify x509.checkIssued only checks metadata (Filip Skokan) [#58457](https://github.com/nodejs/node/pull/58457) +* \[[`5cc97df637`](https://github.com/nodejs/node/commit/5cc97df637)] - **doc**: add links to parent class for `node:zlib` classes (Antoine du Hamel) [#58433](https://github.com/nodejs/node/pull/58433) +* \[[`36e0d5539b`](https://github.com/nodejs/node/commit/36e0d5539b)] - **doc**: remove remaining uses of `@@wellknown` syntax (René) [#58413](https://github.com/nodejs/node/pull/58413) +* \[[`2f36f8e863`](https://github.com/nodejs/node/commit/2f36f8e863)] - **doc**: clarify behavior of --watch-path and --watch flags (Juan Ignacio Benito) [#58136](https://github.com/nodejs/node/pull/58136) +* \[[`3b857735ef`](https://github.com/nodejs/node/commit/3b857735ef)] - **doc**: add JonasBa to collaborators (Jonas Badalic) [#58355](https://github.com/nodejs/node/pull/58355) +* \[[`9d5e969bb6`](https://github.com/nodejs/node/commit/9d5e969bb6)] - **doc**: add latest security release steward (Rafael Gonzaga) [#58339](https://github.com/nodejs/node/pull/58339) +* \[[`b22bb03167`](https://github.com/nodejs/node/commit/b22bb03167)] - **doc**: fix CryptoKey.algorithm type and other interfaces in webcrypto.md (Filip Skokan) [#58294](https://github.com/nodejs/node/pull/58294) +* \[[`670f31060b`](https://github.com/nodejs/node/commit/670f31060b)] - **doc**: mark the callback argument of crypto.generatePrime as mandatory (Allon Murienik) [#58299](https://github.com/nodejs/node/pull/58299) +* \[[`39d9a61239`](https://github.com/nodejs/node/commit/39d9a61239)] - **doc**: remove comma delimiter mention on permissions doc (Rafael Gonzaga) [#58297](https://github.com/nodejs/node/pull/58297) +* \[[`573b0b7bfe`](https://github.com/nodejs/node/commit/573b0b7bfe)] - **doc**: make Stability labels not sticky in Stability index (Livia Medeiros) [#58291](https://github.com/nodejs/node/pull/58291) +* \[[`a5a686a3ae`](https://github.com/nodejs/node/commit/a5a686a3ae)] - **doc**: update commit-queue documentation (Dario Piotrowicz) [#58275](https://github.com/nodejs/node/pull/58275) +* \[[`fdf7612735`](https://github.com/nodejs/node/commit/fdf7612735)] - **doc**: add puskin to collaborators (Giovanni Bucci) [#58308](https://github.com/nodejs/node/pull/58308) +* \[[`be492a1708`](https://github.com/nodejs/node/commit/be492a1708)] - **doc**: update stability status for diagnostics\_channel to experimental (Idan Goshen) [#58261](https://github.com/nodejs/node/pull/58261) +* \[[`7d00fc2206`](https://github.com/nodejs/node/commit/7d00fc2206)] - **doc**: clarify napi\_get\_value\_string\_\* for bufsize 0 (Tobias Nießen) [#58158](https://github.com/nodejs/node/pull/58158) +* \[[`c8500a2c4a`](https://github.com/nodejs/node/commit/c8500a2c4a)] - **doc**: fix typo of file `http.md`, `outgoingMessage.setTimeout` section (yusheng chen) [#58188](https://github.com/nodejs/node/pull/58188) +* \[[`34a9b856c3`](https://github.com/nodejs/node/commit/34a9b856c3)] - **doc**: update return types for eventNames method in EventEmitter (Yukihiro Hasegawa) [#58083](https://github.com/nodejs/node/pull/58083) +* \[[`faedee59d2`](https://github.com/nodejs/node/commit/faedee59d2)] - **doc**: fix typo in benchmark script path (Miguel Marcondes Filho) [#58129](https://github.com/nodejs/node/pull/58129) +* \[[`570d8d3f10`](https://github.com/nodejs/node/commit/570d8d3f10)] - **doc**: clarify future Corepack removal in v25+ (Trivikram Kamat) [#57825](https://github.com/nodejs/node/pull/57825) +* \[[`a71b9fc2ff`](https://github.com/nodejs/node/commit/a71b9fc2ff)] - **doc**: mark multiple APIs stable (James M Snell) [#57513](https://github.com/nodejs/node/pull/57513) +* \[[`73a97d47f3`](https://github.com/nodejs/node/commit/73a97d47f3)] - **doc,lib**: update source map links to ECMA426 (Chengzhong Wu) [#58597](https://github.com/nodejs/node/pull/58597) +* \[[`8b41429499`](https://github.com/nodejs/node/commit/8b41429499)] - **doc,src,test**: fix typos (Noritaka Kobayashi) [#58477](https://github.com/nodejs/node/pull/58477) +* \[[`0cea14ec7f`](https://github.com/nodejs/node/commit/0cea14ec7f)] - **errors**: show url of unsupported attributes in the error message (Aditi) [#58303](https://github.com/nodejs/node/pull/58303) +* \[[`b9586bf898`](https://github.com/nodejs/node/commit/b9586bf898)] - **(SEMVER-MINOR)** **fs**: add autoClose option to FileHandle readableWebStream (James M Snell) [#58548](https://github.com/nodejs/node/pull/58548) +* \[[`72a1b061f3`](https://github.com/nodejs/node/commit/72a1b061f3)] - **fs**: unexpose internal constants (Chengzhong Wu) [#58327](https://github.com/nodejs/node/pull/58327) +* \[[`5c36510dec`](https://github.com/nodejs/node/commit/5c36510dec)] - **fs**: add support for `URL` for `fs.glob`'s `cwd` option (Antoine du Hamel) [#58182](https://github.com/nodejs/node/pull/58182) +* \[[`3642b0d944`](https://github.com/nodejs/node/commit/3642b0d944)] - **fs**: improve cpSync no-filter copyDir performance (Dario Piotrowicz) [#58461](https://github.com/nodejs/node/pull/58461) +* \[[`24865bc7e8`](https://github.com/nodejs/node/commit/24865bc7e8)] - **fs**: improve `cpSync` dest overriding performance (Dario Piotrowicz) [#58160](https://github.com/nodejs/node/pull/58160) +* \[[`1b3847694d`](https://github.com/nodejs/node/commit/1b3847694d)] - **(SEMVER-MINOR)** **fs**: add to `Dir` support for explicit resource management (Antoine du Hamel) [#58206](https://github.com/nodejs/node/pull/58206) +* \[[`cff62e3265`](https://github.com/nodejs/node/commit/cff62e3265)] - **fs**: ensure `dir.read()` does not throw synchronously (Antoine du Hamel) [#58228](https://github.com/nodejs/node/pull/58228) +* \[[`cb39e4ca1f`](https://github.com/nodejs/node/commit/cb39e4ca1f)] - **fs**: glob is stable, so should not emit experimental warnings (Théo LUDWIG) [#58236](https://github.com/nodejs/node/pull/58236) +* \[[`597bfefbe1`](https://github.com/nodejs/node/commit/597bfefbe1)] - **http**: deprecate instantiating classes without new (Yagiz Nizipli) [#58518](https://github.com/nodejs/node/pull/58518) +* \[[`5298da0102`](https://github.com/nodejs/node/commit/5298da0102)] - **http**: remove unused functions and add todos (Yagiz Nizipli) [#58143](https://github.com/nodejs/node/pull/58143) +* \[[`cff440e0fa`](https://github.com/nodejs/node/commit/cff440e0fa)] - **http,https**: give names to anonymous or misnamed functions (Livia Medeiros) [#58180](https://github.com/nodejs/node/pull/58180) +* \[[`43bf1f619a`](https://github.com/nodejs/node/commit/43bf1f619a)] - **http2**: add raw header array support to h2Session.request() (Tim Perry) [#57917](https://github.com/nodejs/node/pull/57917) +* \[[`e8a0f5b063`](https://github.com/nodejs/node/commit/e8a0f5b063)] - **http2**: add lenient flag for RFC-9113 (Carlos Fuentes) [#58116](https://github.com/nodejs/node/pull/58116) +* \[[`49cb90d4a5`](https://github.com/nodejs/node/commit/49cb90d4a5)] - **(SEMVER-MINOR)** **http2**: add diagnostics channel 'http2.server.stream.finish' (Darshan Sen) [#58560](https://github.com/nodejs/node/pull/58560) +* \[[`6a56c68728`](https://github.com/nodejs/node/commit/6a56c68728)] - **http2**: add diagnostics channel 'http2.server.stream.error' (Darshan Sen) [#58512](https://github.com/nodejs/node/pull/58512) +* \[[`59806b41d3`](https://github.com/nodejs/node/commit/59806b41d3)] - **http2**: add diagnostics channel 'http2.server.stream.start' (Darshan Sen) [#58449](https://github.com/nodejs/node/pull/58449) +* \[[`d3d662ae47`](https://github.com/nodejs/node/commit/d3d662ae47)] - **http2**: remove no longer userful options.selectPadding (Jimmy Leung) [#58373](https://github.com/nodejs/node/pull/58373) +* \[[`dec6c9af8c`](https://github.com/nodejs/node/commit/dec6c9af8c)] - **http2**: add diagnostics channel 'http2.server.stream.created' (Darshan Sen) [#58390](https://github.com/nodejs/node/pull/58390) +* \[[`9e98899986`](https://github.com/nodejs/node/commit/9e98899986)] - **http2**: add diagnostics channel 'http2.client.stream.close' (Darshan Sen) [#58329](https://github.com/nodejs/node/pull/58329) +* \[[`86610389d8`](https://github.com/nodejs/node/commit/86610389d8)] - **http2**: add diagnostics channel 'http2.client.stream.finish' (Darshan Sen) [#58317](https://github.com/nodejs/node/pull/58317) +* \[[`2d3071671e`](https://github.com/nodejs/node/commit/2d3071671e)] - **http2**: add diagnostics channel 'http2.client.stream.error' (Darshan Sen) [#58306](https://github.com/nodejs/node/pull/58306) +* \[[`6c3e426d6f`](https://github.com/nodejs/node/commit/6c3e426d6f)] - **http2**: add diagnostics channel 'http2.client.stream.start' (Darshan Sen) [#58292](https://github.com/nodejs/node/pull/58292) +* \[[`b99d131a61`](https://github.com/nodejs/node/commit/b99d131a61)] - **http2**: add diagnostics channel 'http2.client.stream.created' (Darshan Sen) [#58246](https://github.com/nodejs/node/pull/58246) +* \[[`b0644330f5`](https://github.com/nodejs/node/commit/b0644330f5)] - **http2**: give name to promisified `connect()` (LiviaMedeiros) [#57916](https://github.com/nodejs/node/pull/57916) +* \[[`4092d3611a`](https://github.com/nodejs/node/commit/4092d3611a)] - **inspector**: add mimeType and charset support to Network.Response (Shima Ryuhei) [#58192](https://github.com/nodejs/node/pull/58192) +* \[[`d7d8599f7c`](https://github.com/nodejs/node/commit/d7d8599f7c)] - **inspector**: add protocol method Network.dataReceived (Chengzhong Wu) [#58001](https://github.com/nodejs/node/pull/58001) +* \[[`aabafbc28f`](https://github.com/nodejs/node/commit/aabafbc28f)] - **inspector**: support for worker inspection in chrome devtools (Shima Ryuhei) [#56759](https://github.com/nodejs/node/pull/56759) +* \[[`20d978de9a`](https://github.com/nodejs/node/commit/20d978de9a)] - **lib**: make ERM functions into wrappers returning undefined (Livia Medeiros) [#58400](https://github.com/nodejs/node/pull/58400) +* \[[`13567eac5f`](https://github.com/nodejs/node/commit/13567eac5f)] - **(SEMVER-MINOR)** **lib**: graduate error codes that have been around for years (James M Snell) [#58541](https://github.com/nodejs/node/pull/58541) +* \[[`342b5a0d7a`](https://github.com/nodejs/node/commit/342b5a0d7a)] - **lib**: remove no-mixed-operators eslint rule (Ruben Bridgewater) [#58375](https://github.com/nodejs/node/pull/58375) +* \[[`af7baef75a`](https://github.com/nodejs/node/commit/af7baef75a)] - **lib**: fix sourcemaps with ts module mocking (Marco Ippolito) [#58193](https://github.com/nodejs/node/pull/58193) +* \[[`8f73f42d4e`](https://github.com/nodejs/node/commit/8f73f42d4e)] - **meta**: bump github/codeql-action from 3.28.16 to 3.28.18 (dependabot\[bot]) [#58552](https://github.com/nodejs/node/pull/58552) +* \[[`5dfedbeb86`](https://github.com/nodejs/node/commit/5dfedbeb86)] - **meta**: bump codecov/codecov-action from 5.4.2 to 5.4.3 (dependabot\[bot]) [#58551](https://github.com/nodejs/node/pull/58551) +* \[[`53c50f66f5`](https://github.com/nodejs/node/commit/53c50f66f5)] - **meta**: bump step-security/harden-runner from 2.11.0 to 2.12.0 (dependabot\[bot]) [#58109](https://github.com/nodejs/node/pull/58109) +* \[[`a1a7024831`](https://github.com/nodejs/node/commit/a1a7024831)] - **meta**: bump ossf/scorecard-action from 2.4.1 to 2.4.2 (dependabot\[bot]) [#58550](https://github.com/nodejs/node/pull/58550) +* \[[`a379988ef6`](https://github.com/nodejs/node/commit/a379988ef6)] - **meta**: bump rtCamp/action-slack-notify from 2.3.2 to 2.3.3 (dependabot\[bot]) [#58108](https://github.com/nodejs/node/pull/58108) +* \[[`f6a46c87f2`](https://github.com/nodejs/node/commit/f6a46c87f2)] - **meta**: move one or more collaborators to emeritus (Node.js GitHub Bot) [#58456](https://github.com/nodejs/node/pull/58456) +* \[[`98b6aa0dcd`](https://github.com/nodejs/node/commit/98b6aa0dcd)] - **meta**: bump github/codeql-action from 3.28.11 to 3.28.16 (dependabot\[bot]) [#58112](https://github.com/nodejs/node/pull/58112) +* \[[`5202b262e3`](https://github.com/nodejs/node/commit/5202b262e3)] - **meta**: bump codecov/codecov-action from 5.4.0 to 5.4.2 (dependabot\[bot]) [#58110](https://github.com/nodejs/node/pull/58110) +* \[[`d97616ac6e`](https://github.com/nodejs/node/commit/d97616ac6e)] - **meta**: bump actions/download-artifact from 4.2.1 to 4.3.0 (dependabot\[bot]) [#58106](https://github.com/nodejs/node/pull/58106) +* \[[`f4065074cf`](https://github.com/nodejs/node/commit/f4065074cf)] - **meta**: ignore mailmap changes in linux ci (Jonas Badalic) [#58356](https://github.com/nodejs/node/pull/58356) +* \[[`e6d1224e54`](https://github.com/nodejs/node/commit/e6d1224e54)] - **meta**: bump actions/setup-node from 4.3.0 to 4.4.0 (dependabot\[bot]) [#58111](https://github.com/nodejs/node/pull/58111) +* \[[`26da160ab2`](https://github.com/nodejs/node/commit/26da160ab2)] - **meta**: bump actions/setup-python from 5.5.0 to 5.6.0 (dependabot\[bot]) [#58107](https://github.com/nodejs/node/pull/58107) +* \[[`4cc4195493`](https://github.com/nodejs/node/commit/4cc4195493)] - **module**: handle instantiated async module jobs in require(esm) (Joyee Cheung) [#58067](https://github.com/nodejs/node/pull/58067) +* \[[`72fac71b92`](https://github.com/nodejs/node/commit/72fac71b92)] - **module**: clarify cjs global-like error on ModuleJobSync (Carlos Espa) [#56491](https://github.com/nodejs/node/pull/56491) +* \[[`fecd841c93`](https://github.com/nodejs/node/commit/fecd841c93)] - **net**: always publish to 'net.client.socket' diagnostics channel (Darshan Sen) [#58349](https://github.com/nodejs/node/pull/58349) +* \[[`25ee328d2b`](https://github.com/nodejs/node/commit/25ee328d2b)] - **path**: improve path.resolve() performance when used as process.cwd() (Ruben Bridgewater) [#58362](https://github.com/nodejs/node/pull/58362) +* \[[`6fd1b23260`](https://github.com/nodejs/node/commit/6fd1b23260)] - **permission**: remove useless conditional (Juan José) [#58514](https://github.com/nodejs/node/pull/58514) +* \[[`5b2cca51a3`](https://github.com/nodejs/node/commit/5b2cca51a3)] - **report**: use uv\_getrusage\_thread in report (theanarkh) [#58405](https://github.com/nodejs/node/pull/58405) +* \[[`63ec23e84b`](https://github.com/nodejs/node/commit/63ec23e84b)] - **sqlite**: add build option to build without sqlite (Michael Dawson) [#58122](https://github.com/nodejs/node/pull/58122) +* \[[`9d8677bff5`](https://github.com/nodejs/node/commit/9d8677bff5)] - **sqlite**: handle thrown errors in result callback (Colin Ihrig) [#58426](https://github.com/nodejs/node/pull/58426) +* \[[`3490c75760`](https://github.com/nodejs/node/commit/3490c75760)] - **sqlite**: set `name` and `length` on `sqlite.backup()` (Livia Medeiros) [#58251](https://github.com/nodejs/node/pull/58251) +* \[[`50bdd94e0b`](https://github.com/nodejs/node/commit/50bdd94e0b)] - **src**: update std::vector\> to use v8::LocalVector\ (Aditi) [#58500](https://github.com/nodejs/node/pull/58500) +* \[[`7de58417cc`](https://github.com/nodejs/node/commit/7de58417cc)] - **src**: env\_vars caching and local variable scope optimization (Mert Can Altin) [#57624](https://github.com/nodejs/node/pull/57624) +* \[[`6d99ec33a4`](https://github.com/nodejs/node/commit/6d99ec33a4)] - **src**: fix FIPS init error handling (Tobias Nießen) [#58379](https://github.com/nodejs/node/pull/58379) +* \[[`4c23a9575e`](https://github.com/nodejs/node/commit/4c23a9575e)] - **src**: fix possible dereference of null pointer (Eusgor) [#58459](https://github.com/nodejs/node/pull/58459) +* \[[`eb143e902b`](https://github.com/nodejs/node/commit/eb143e902b)] - **src**: fix -Wreturn-stack-address error (Shelley Vohr) [#58439](https://github.com/nodejs/node/pull/58439) +* \[[`31058b8785`](https://github.com/nodejs/node/commit/31058b8785)] - **src**: reorganize ContextifyFunction methods (Chengzhong Wu) [#58434](https://github.com/nodejs/node/pull/58434) +* \[[`7521077299`](https://github.com/nodejs/node/commit/7521077299)] - **src**: improve CompileFunctionAndCacheResult error handling (Chengzhong Wu) [#58434](https://github.com/nodejs/node/pull/58434) +* \[[`0c9efccb12`](https://github.com/nodejs/node/commit/0c9efccb12)] - **src**: fix build when using shared simdutf (Antoine du Hamel) [#58407](https://github.com/nodejs/node/pull/58407) +* \[[`aa00f5946f`](https://github.com/nodejs/node/commit/aa00f5946f)] - **src**: add a variant of ToV8Value() for primitive arrays (Aditi) [#57576](https://github.com/nodejs/node/pull/57576) +* \[[`29a11506fc`](https://github.com/nodejs/node/commit/29a11506fc)] - **src**: remove unused `checkMessagePort` internal binding (Dario Piotrowicz) [#58267](https://github.com/nodejs/node/pull/58267) +* \[[`0ce3feed5b`](https://github.com/nodejs/node/commit/0ce3feed5b)] - **src**: remove unused `shouldRetryAsESM` internal binding (Dario Piotrowicz) [#58265](https://github.com/nodejs/node/pull/58265) +* \[[`517219613d`](https://github.com/nodejs/node/commit/517219613d)] - **src**: add a couple fast apis in node\_os (James M Snell) [#58210](https://github.com/nodejs/node/pull/58210) +* \[[`3f834da09e`](https://github.com/nodejs/node/commit/3f834da09e)] - **src**: fix module buffer allocation (X-BW) [#57738](https://github.com/nodejs/node/pull/57738) +* \[[`a793706db0`](https://github.com/nodejs/node/commit/a793706db0)] - **src**: remove overzealous tcsetattr error check (Ben Noordhuis) [#58200](https://github.com/nodejs/node/pull/58200) +* \[[`5656c74517`](https://github.com/nodejs/node/commit/5656c74517)] - **src**: remove NonCopyableMaybe (Tobias Nießen) [#58168](https://github.com/nodejs/node/pull/58168) +* \[[`cab242334b`](https://github.com/nodejs/node/commit/cab242334b)] - **src**: improve parsing of boolean options (Edy Silva) [#58039](https://github.com/nodejs/node/pull/58039) +* \[[`a5df778150`](https://github.com/nodejs/node/commit/a5df778150)] - **src,lib**: obtain sourceURL in magic comments from V8 (Chengzhong Wu) [#58389](https://github.com/nodejs/node/pull/58389) +* \[[`bd6743b434`](https://github.com/nodejs/node/commit/bd6743b434)] - **src,permission**: implicit allow-fs-read to app entrypoint (Rafael Gonzaga) [#58579](https://github.com/nodejs/node/pull/58579) +* \[[`5bd99e4a4d`](https://github.com/nodejs/node/commit/5bd99e4a4d)] - **stream**: making DecompressionStream spec compilent for trailing junk (0hm☘️) [#58316](https://github.com/nodejs/node/pull/58316) +* \[[`6582b19488`](https://github.com/nodejs/node/commit/6582b19488)] - **test**: reduce flakiness in test-heapdump-http2 (Joyee Cheung) [#58148](https://github.com/nodejs/node/pull/58148) +* \[[`0f6a262744`](https://github.com/nodejs/node/commit/0f6a262744)] - **test**: improve flakiness detection on stack corruption tests (Darshan Sen) [#58601](https://github.com/nodejs/node/pull/58601) +* \[[`983affaea2`](https://github.com/nodejs/node/commit/983affaea2)] - **test**: mark timeouts & flaky test as flaky on IBM i (Abdirahim Musse) [#58583](https://github.com/nodejs/node/pull/58583) +* \[[`3603362b6f`](https://github.com/nodejs/node/commit/3603362b6f)] - **test**: rewrite test-child-process-spawn-args (Michaël Zasso) [#58546](https://github.com/nodejs/node/pull/58546) +* \[[`93900b0c17`](https://github.com/nodejs/node/commit/93900b0c17)] - **test**: make sqlite-database-sync tests work with system sqlite (Jelle Licht) [#58507](https://github.com/nodejs/node/pull/58507) +* \[[`7d505f4185`](https://github.com/nodejs/node/commit/7d505f4185)] - **test**: force slow JSON.stringify path for overflow (Shelley Vohr) [#58181](https://github.com/nodejs/node/pull/58181) +* \[[`2e8570b8f9`](https://github.com/nodejs/node/commit/2e8570b8f9)] - **test**: account for truthy signal in flaky async\_hooks tests (Darshan Sen) [#58478](https://github.com/nodejs/node/pull/58478) +* \[[`1f1e194c0f`](https://github.com/nodejs/node/commit/1f1e194c0f)] - **test**: update WPT for WebCryptoAPI to 591c95ce61 (Node.js GitHub Bot) [#58176](https://github.com/nodejs/node/pull/58176) +* \[[`d822632d91`](https://github.com/nodejs/node/commit/d822632d91)] - **test**: remove --no-warnings flag (Tobias Nießen) [#58424](https://github.com/nodejs/node/pull/58424) +* \[[`01377713d7`](https://github.com/nodejs/node/commit/01377713d7)] - **test**: add tests ensuring worker threads cannot access internals (Joe) [#58332](https://github.com/nodejs/node/pull/58332) +* \[[`99a20902fc`](https://github.com/nodejs/node/commit/99a20902fc)] - **test**: leverage process.features.openssl\_is\_boringssl in test (Shelley Vohr) [#58421](https://github.com/nodejs/node/pull/58421) +* \[[`b3e0cf1b15`](https://github.com/nodejs/node/commit/b3e0cf1b15)] - **test**: fix test-buffer-tostring-range on allocation failure (Joyee Cheung) [#58416](https://github.com/nodejs/node/pull/58416) +* \[[`1d4b3451c5`](https://github.com/nodejs/node/commit/1d4b3451c5)] - **test**: skip in test-buffer-tostring-rangeerror on allocation failure (Joyee Cheung) [#58415](https://github.com/nodejs/node/pull/58415) +* \[[`612c393c71`](https://github.com/nodejs/node/commit/612c393c71)] - **test**: fix missing edge case in test-blob-slice-with-large-size (Joyee Cheung) [#58414](https://github.com/nodejs/node/pull/58414) +* \[[`b11b9cdad8`](https://github.com/nodejs/node/commit/b11b9cdad8)] - **test**: make crypto tests work with BoringSSL (Shelley Vohr) [#58117](https://github.com/nodejs/node/pull/58117) +* \[[`99711ee548`](https://github.com/nodejs/node/commit/99711ee548)] - **test**: test reordering of setAAD and setAuthTag (Tobias Nießen) [#58396](https://github.com/nodejs/node/pull/58396) +* \[[`828aaaa3f7`](https://github.com/nodejs/node/commit/828aaaa3f7)] - **test**: switch from deprecated `optparse` to `argparse` (Aviv Keller) [#58224](https://github.com/nodejs/node/pull/58224) +* \[[`9af305408e`](https://github.com/nodejs/node/commit/9af305408e)] - **test**: do not skip OCB decryption in FIPS mode (Tobias Nießen) [#58382](https://github.com/nodejs/node/pull/58382) +* \[[`9527c876bf`](https://github.com/nodejs/node/commit/9527c876bf)] - **test**: show more information in test-http2-debug upon failure (Joyee Cheung) [#58391](https://github.com/nodejs/node/pull/58391) +* \[[`9be0601112`](https://github.com/nodejs/node/commit/9be0601112)] - **test**: remove loop over single element (Tobias Nießen) [#58368](https://github.com/nodejs/node/pull/58368) +* \[[`40a03d3d14`](https://github.com/nodejs/node/commit/40a03d3d14)] - **test**: add chacha20-poly1305 to auth tag order test (Tobias Nießen) [#58367](https://github.com/nodejs/node/pull/58367) +* \[[`cccb15df7e`](https://github.com/nodejs/node/commit/cccb15df7e)] - **test**: skip wasm-allocation tests for pointer compression builds (Joyee Cheung) [#58171](https://github.com/nodejs/node/pull/58171) +* \[[`f18041ae8e`](https://github.com/nodejs/node/commit/f18041ae8e)] - **test**: remove references to create(De|C)ipher (Tobias Nießen) [#58363](https://github.com/nodejs/node/pull/58363) +* \[[`ca8d66c1fc`](https://github.com/nodejs/node/commit/ca8d66c1fc)] - **test**: remove unnecessary `console.log` from test-repl-null-thrown (Dario Piotrowicz) [#58281](https://github.com/nodejs/node/pull/58281) +* \[[`455372023d`](https://github.com/nodejs/node/commit/455372023d)] - **test**: allow `tmpDir.path` to be modified (Aviv Keller) [#58173](https://github.com/nodejs/node/pull/58173) +* \[[`1f1fab60c7`](https://github.com/nodejs/node/commit/1f1fab60c7)] - **test**: fix executable flags (Livia Medeiros) [#58250](https://github.com/nodejs/node/pull/58250) +* \[[`8bafc0f061`](https://github.com/nodejs/node/commit/8bafc0f061)] - **test**: deflake test-http2-client-socket-destroy (Luigi Pinca) [#58212](https://github.com/nodejs/node/pull/58212) +* \[[`97aac9f17a`](https://github.com/nodejs/node/commit/97aac9f17a)] - **test**: skip test-buffer-tostring-rangeerror when low on memory (Ruben Bridgewater) [#58142](https://github.com/nodejs/node/pull/58142) +* \[[`2896760da1`](https://github.com/nodejs/node/commit/2896760da1)] - **test**: mark `test-http2-debug` as flaky on LinuxONE (Richard Lau) [#58494](https://github.com/nodejs/node/pull/58494) +* \[[`7327d14780`](https://github.com/nodejs/node/commit/7327d14780)] - **test**: reduce iteration count in test-child-process-stdout-flush-exit (Antoine du Hamel) [#58273](https://github.com/nodejs/node/pull/58273) +* \[[`1bd7a2edf9`](https://github.com/nodejs/node/commit/1bd7a2edf9)] - **test\_runner**: support mocking json modules (Jacob Smith) [#58007](https://github.com/nodejs/node/pull/58007) +* \[[`a3877c53b1`](https://github.com/nodejs/node/commit/a3877c53b1)] - **test\_runner**: add level parameter to reporter.diagnostic (Jacopo Martinelli) [#57923](https://github.com/nodejs/node/pull/57923) +* \[[`253772c2d9`](https://github.com/nodejs/node/commit/253772c2d9)] - **tools**: bump the eslint group in `/tools/eslint` with 6 updates (dependabot\[bot]) [#58549](https://github.com/nodejs/node/pull/58549) +* \[[`b7feda97b0`](https://github.com/nodejs/node/commit/b7feda97b0)] - **tools**: disable failing coverage jobs (Antoine du Hamel) [#58770](https://github.com/nodejs/node/pull/58770) +* \[[`8a47096093`](https://github.com/nodejs/node/commit/8a47096093)] - **tools**: ignore `deps/` and `benchmark/` for CodeQL (Rafael Gonzaga) [#58254](https://github.com/nodejs/node/pull/58254) +* \[[`70be158126`](https://github.com/nodejs/node/commit/70be158126)] - **tools**: add read permission to workflows that read contents (Antoine du Hamel) [#58255](https://github.com/nodejs/node/pull/58255) +* \[[`e4373be766`](https://github.com/nodejs/node/commit/e4373be766)] - **tools**: exclude deps/v8/tools from CodeQL scans (Rich Trott) [#58132](https://github.com/nodejs/node/pull/58132) +* \[[`23ceb364d4`](https://github.com/nodejs/node/commit/23ceb364d4)] - **tools**: bump the eslint group in /tools/eslint with 6 updates (dependabot\[bot]) [#58105](https://github.com/nodejs/node/pull/58105) +* \[[`5b6ced3255`](https://github.com/nodejs/node/commit/5b6ced3255)] - **tty**: improve color terminal color detection (Ruben Bridgewater) [#58146](https://github.com/nodejs/node/pull/58146) +* \[[`7be70979c6`](https://github.com/nodejs/node/commit/7be70979c6)] - **tty**: use terminal VT mode on Windows (Anna Henningsen) [#58358](https://github.com/nodejs/node/pull/58358) +* \[[`b7d7ffe793`](https://github.com/nodejs/node/commit/b7d7ffe793)] - **typings**: add inspector internalBinding typing (Shima Ryuhei) [#58492](https://github.com/nodejs/node/pull/58492) +* \[[`0056d1a2e2`](https://github.com/nodejs/node/commit/0056d1a2e2)] - **typings**: remove no longer valid `FixedSizeBlobCopyJob` type (Dario Piotrowicz) [#58305](https://github.com/nodejs/node/pull/58305) +* \[[`581c0738f9`](https://github.com/nodejs/node/commit/581c0738f9)] - **typings**: remove no longer valid `revokeDataObject` type (Dario Piotrowicz) [#58305](https://github.com/nodejs/node/pull/58305) +* \[[`1db1c870f0`](https://github.com/nodejs/node/commit/1db1c870f0)] - **typings**: add missing typings for `TypedArray` (Jason Zhang) [#58248](https://github.com/nodejs/node/pull/58248) +* \[[`6d3f43c9a6`](https://github.com/nodejs/node/commit/6d3f43c9a6)] - **url**: improve performance of the format function (Giovanni Bucci) [#57099](https://github.com/nodejs/node/pull/57099) +* \[[`54288bdb42`](https://github.com/nodejs/node/commit/54288bdb42)] - **(SEMVER-MINOR)** **util**: add 'none' style to styleText (James M Snell) [#58437](https://github.com/nodejs/node/pull/58437) +* \[[`6af5358f9c`](https://github.com/nodejs/node/commit/6af5358f9c)] - **util**: add internal `assignFunctionName()` function (LiviaMedeiros) [#57916](https://github.com/nodejs/node/pull/57916) +* \[[`9f2e5aad38`](https://github.com/nodejs/node/commit/9f2e5aad38)] - **vm**: import call should return a promise in the current context (Chengzhong Wu) [#58309](https://github.com/nodejs/node/pull/58309) +* \[[`92304a5e62`](https://github.com/nodejs/node/commit/92304a5e62)] - **watch**: fix watch args not being properly filtered (Dario Piotrowicz) [#58279](https://github.com/nodejs/node/pull/58279) +* \[[`539df8e98d`](https://github.com/nodejs/node/commit/539df8e98d)] - **win,tools**: use Azure Trusted Signing (Stefan Stojanovic) [#58502](https://github.com/nodejs/node/pull/58502) +* \[[`ef66357637`](https://github.com/nodejs/node/commit/ef66357637)] - **worker**: give names to `MessagePort` functions (Livia Medeiros) [#58307](https://github.com/nodejs/node/pull/58307) +* \[[`b3cd847528`](https://github.com/nodejs/node/commit/b3cd847528)] - **zlib**: remove mentions of unexposed Z\_TREES constant (Jimmy Leung) [#58371](https://github.com/nodejs/node/pull/58371) + ## 2025-05-21, Version 22.16.0 'Jod' (LTS), @aduh95 diff --git a/doc/contributing/commit-queue.md b/doc/contributing/commit-queue.md index cece9ea84e94f8..a47b1d84f29a5f 100644 --- a/doc/contributing/commit-queue.md +++ b/doc/contributing/commit-queue.md @@ -1,10 +1,8 @@ # Commit queue -> Stability: 1 - Experimental - _tl;dr: You can land pull requests by adding the `commit-queue` label to it._ -Commit Queue is an experimental feature for the project which simplifies the +Commit Queue is a feature for the project which simplifies the landing process by automating it via GitHub Actions. With it, collaborators can land pull requests by adding the `commit-queue` label to a PR. All checks will run via `@node-core/utils`, and if the pull request is ready to @@ -18,7 +16,7 @@ implementation details, reasoning for design choices, and current limitations. From a high-level, the Commit Queue works as follow: 1. Collaborators will add `commit-queue` label to pull requests ready to land -2. Every five minutes the queue will do the following for each pull request +2. Every five minutes the queue will do the following for each mergeable pull request with the label: 1. Check if the PR also has a `request-ci` label (if it has, skip this PR since it's pending a CI run) diff --git a/doc/contributing/primordials.md b/doc/contributing/primordials.md index bbffca00806c66..4b143c485ff9d9 100644 --- a/doc/contributing/primordials.md +++ b/doc/contributing/primordials.md @@ -161,8 +161,9 @@ This code is internally expanded into something that looks like: ```js { - // 1. Lookup @@iterator property on `array` (user-mutable if user-provided). - // 2. Lookup @@iterator property on %Array.prototype% (user-mutable). + // 1. Lookup %Symbol.iterator% property on `array` (user-mutable if + // user-provided). + // 2. Lookup %Symbol.iterator% property on %Array.prototype% (user-mutable). // 3. Call that function. const iterator = array[Symbol.iterator](); // 1. Lookup `next` property on `iterator` (doesn't exist). @@ -226,8 +227,9 @@ const [first, second] = array; This is roughly equivalent to: ```js -// 1. Lookup @@iterator property on `array` (user-mutable if user-provided). -// 2. Lookup @@iterator property on %Array.prototype% (user-mutable). +// 1. Lookup %Symbol.iterator% property on `array` (user-mutable if +// user-provided). +// 2. Lookup %Symbol.iterator% property on %Array.prototype% (user-mutable). // 3. Call that function. const iterator = array[Symbol.iterator](); // 1. Lookup `next` property on `iterator` (doesn't exist). @@ -262,8 +264,9 @@ best choice. Avoid spread operator on arrays ```js -// 1. Lookup @@iterator property on `array` (user-mutable if user-provided). -// 2. Lookup @@iterator property on %Array.prototype% (user-mutable). +// 1. Lookup %Symbol.iterator% property on `array` (user-mutable if +// user-provided). +// 2. Lookup %Symbol.iterator% property on %Array.prototype% (user-mutable). // 3. Lookup `next` property on %ArrayIteratorPrototype% (user-mutable). const arrayCopy = [...array]; func(...array); @@ -281,17 +284,17 @@ ReflectApply(func, null, array);
    %Array.prototype.concat% looks up - @@isConcatSpreadable property of the passed - arguments and the this value. + %Symbol.isConcatSpreadable% property of the passed + arguments and the this value ```js { // Unsafe code example: - // 1. Lookup @@isConcatSpreadable property on `array` (user-mutable if - // user-provided). - // 2. Lookup @@isConcatSpreadable property on `%Array.prototype% + // 1. Lookup %Symbol.isConcatSpreadable% property on `array` + // (user-mutable if user-provided). + // 2. Lookup %Symbol.isConcatSpreadable% property on `%Array.prototype% // (user-mutable). - // 2. Lookup @@isConcatSpreadable property on `%Object.prototype% + // 2. Lookup %Symbol.isConcatSpreadable% property on `%Object.prototype% // (user-mutable). const array = []; ArrayPrototypeConcat(array); @@ -340,8 +343,9 @@ Object.defineProperty(Object.prototype, Symbol.isConcatSpreadable, { ```js { // Unsafe code example: - // 1. Lookup @@iterator property on `array` (user-mutable if user-provided). - // 2. Lookup @@iterator property on %Array.prototype% (user-mutable). + // 1. Lookup %Symbol.iterator% property on `array` (user-mutable if + // user-provided). + // 2. Lookup %Symbol.iterator% property on %Array.prototype% (user-mutable). // 3. Lookup `next` property on %ArrayIteratorPrototype% (user-mutable). const obj = ObjectFromEntries(array); } @@ -371,8 +375,9 @@ Object.defineProperty(Object.prototype, Symbol.isConcatSpreadable, { %Promise.race% iterate over an array ```js -// 1. Lookup @@iterator property on `array` (user-mutable if user-provided). -// 2. Lookup @@iterator property on %Array.prototype% (user-mutable). +// 1. Lookup %Symbol.iterator% property on `array` (user-mutable if +// user-provided). +// 2. Lookup %Symbol.iterator% property on %Array.prototype% (user-mutable). // 3. Lookup `next` property on %ArrayIteratorPrototype% (user-mutable). // 4. Lookup `then` property on %Array.Prototype% (user-mutable). // 5. Lookup `then` property on %Object.Prototype% (user-mutable). @@ -437,7 +442,7 @@ Array.prototype[Symbol.iterator] = () => ({ // Core -// 1. Lookup @@iterator property on %Array.prototype% (user-mutable). +// 1. Lookup %Symbol.iterator% property on %Array.prototype% (user-mutable). // 2. Lookup `next` property on %ArrayIteratorPrototype% (user-mutable). const set = new SafeSet([1, 2, 3]); @@ -684,14 +689,14 @@ can be reset from user-land. List of RegExp methods that look up properties from mutable getters -| `RegExp` method | looks up the following flag-related properties | -| ------------------------------ | ------------------------------------------------------------------ | -| `get RegExp.prototype.flags` | `global`, `ignoreCase`, `multiline`, `dotAll`, `unicode`, `sticky` | -| `RegExp.prototype[@@match]` | `global`, `unicode` | -| `RegExp.prototype[@@matchAll]` | `flags` | -| `RegExp.prototype[@@replace]` | `global`, `unicode` | -| `RegExp.prototype[@@split]` | `flags` | -| `RegExp.prototype.toString` | `flags` | +| `RegExp` method | looks up the following flag-related properties | +| ----------------------------------- | ------------------------------------------------------------------ | +| `get RegExp.prototype.flags` | `global`, `ignoreCase`, `multiline`, `dotAll`, `unicode`, `sticky` | +| `RegExp.prototype[Symbol.match]` | `global`, `unicode` | +| `RegExp.prototype[Symbol.matchAll]` | `flags` | +| `RegExp.prototype[Symbol.replace]` | `global`, `unicode` | +| `RegExp.prototype[Symbol.split]` | `flags` | +| `RegExp.prototype.toString` | `flags` |
    @@ -786,7 +791,7 @@ console.log(proxyWithNullPrototypeObject.someProperty); // genuine value ### Checking if an object is an instance of a class -#### Using `instanceof` looks up the `@@hasInstance` property of the class +#### Using `instanceof` looks up the `%Symbol.hasInstance%` property of the class ```js // User-land diff --git a/doc/contributing/releases.md b/doc/contributing/releases.md index de56e5acd17c12..6488c1d51a983f 100644 --- a/doc/contributing/releases.md +++ b/doc/contributing/releases.md @@ -735,15 +735,34 @@ the build before moving forward. Use the following list as a baseline: ### 11. Tag and sign the release commit Once you have produced builds that you're happy with you can either run -`git node release --promote` +`git node release --promote`: ```bash -git node release -S --promote https://github.com/nodejs/node/pull/XXXX +git node release --promote https://github.com/nodejs/node/pull/XXXX -S ``` to automate the remaining steps until step 16 or you can perform it manually following the below steps. +
    +Security release + +For security releases, NCU should be configured to target the public repository, +not the private one where the proposal are hosted. Pass the upstream where to +fetch the proposal from using the `--fetch-from` flag. + +When promoting several releases, you can pass multiple URLs: + +```bash +git node release --promote \ + --fetch-from git@github.com:nodejs-private/node-private.git \ + https://github.com/nodejs-private/node-private/pull/XXXX \ + https://github.com/nodejs-private/node-private/pull/XXXX \ + -S +``` + +
    + *** Create a new tag: By waiting until this stage to create tags, you can discard diff --git a/doc/contributing/security-release-process.md b/doc/contributing/security-release-process.md index 66078c255fb238..0903557a1de181 100644 --- a/doc/contributing/security-release-process.md +++ b/doc/contributing/security-release-process.md @@ -36,6 +36,7 @@ The current security stewards are documented in the main Node.js | NodeSource | Rafael | 2024-Apr-10 | | NodeSource | Rafael | 2024-Jul-08 | | NodeSource | Rafael | 2025-Jan-21 | +| NodeSource | Rafael | 2025-May-14 | | Datadog | Bryan | | | IBM | Joe | | | Platformatic | Matteo | | diff --git a/doc/contributing/writing-and-running-benchmarks.md b/doc/contributing/writing-and-running-benchmarks.md index 63fbf75c798833..1ff494c7c4d90f 100644 --- a/doc/contributing/writing-and-running-benchmarks.md +++ b/doc/contributing/writing-and-running-benchmarks.md @@ -101,7 +101,7 @@ benchmarks. This increases the likelihood of each benchmark achieving peak perfo according to the hardware. Therefore, run: ```console -$ ./benchmarks/cpu.sh fast +$ ./benchmark/cpu.sh fast ``` ### Running individual benchmarks diff --git a/lib/_http_outgoing.js b/lib/_http_outgoing.js index c7dbc3a6ac82eb..943025708b2033 100644 --- a/lib/_http_outgoing.js +++ b/lib/_http_outgoing.js @@ -71,6 +71,7 @@ const { hideStackFrames, } = require('internal/errors'); const { validateString } = require('internal/validators'); +const { assignFunctionName } = internalUtil; const { isUint8Array } = require('internal/util/types'); let debug = require('internal/util/debuglog').debuglog('http', (fn) => { @@ -312,14 +313,14 @@ OutgoingMessage.prototype._renderHeaders = function _renderHeaders() { return headers; }; -OutgoingMessage.prototype.cork = function() { +OutgoingMessage.prototype.cork = function cork() { this[kCorked]++; if (this[kSocket]) { this[kSocket].cork(); } }; -OutgoingMessage.prototype.uncork = function() { +OutgoingMessage.prototype.uncork = function uncork() { this[kCorked]--; if (this[kSocket]) { this[kSocket].uncork(); @@ -664,13 +665,13 @@ function matchHeader(self, state, field, value) { } } -const validateHeaderName = hideStackFrames((name, label) => { +const validateHeaderName = assignFunctionName('validateHeaderName', hideStackFrames((name, label) => { if (typeof name !== 'string' || !name || !checkIsHttpToken(name)) { throw new ERR_INVALID_HTTP_TOKEN.HideStackFramesError(label || 'Header name', name); } -}); +})); -const validateHeaderValue = hideStackFrames((name, value) => { +const validateHeaderValue = assignFunctionName('validateHeaderValue', hideStackFrames((name, value) => { if (value === undefined) { throw new ERR_HTTP_INVALID_HEADER_VALUE.HideStackFramesError(value, name); } @@ -678,7 +679,7 @@ const validateHeaderValue = hideStackFrames((name, value) => { debug('Header "%s" contains invalid characters', name); throw new ERR_INVALID_CHAR.HideStackFramesError('header content', name); } -}); +})); function parseUniqueHeadersOption(headers) { if (!ArrayIsArray(headers)) { diff --git a/lib/_http_server.js b/lib/_http_server.js index 447098e453026f..a7ef03a1ce04f6 100644 --- a/lib/_http_server.js +++ b/lib/_http_server.js @@ -79,6 +79,7 @@ const { }, } = require('internal/errors'); const { + assignFunctionName, kEmptyObject, promisify, SymbolAsyncDispose, @@ -573,17 +574,17 @@ function Server(options, requestListener) { ObjectSetPrototypeOf(Server.prototype, net.Server.prototype); ObjectSetPrototypeOf(Server, net.Server); -Server.prototype.close = function() { +Server.prototype.close = function close() { httpServerPreClose(this); ReflectApply(net.Server.prototype.close, this, arguments); return this; }; -Server.prototype[SymbolAsyncDispose] = async function() { - return promisify(this.close).call(this); -}; +Server.prototype[SymbolAsyncDispose] = assignFunctionName(SymbolAsyncDispose, async function() { + await promisify(this.close).call(this); +}); -Server.prototype.closeAllConnections = function() { +Server.prototype.closeAllConnections = function closeAllConnections() { if (!this[kConnections]) { return; } @@ -595,7 +596,7 @@ Server.prototype.closeAllConnections = function() { } }; -Server.prototype.closeIdleConnections = function() { +Server.prototype.closeIdleConnections = function closeIdleConnections() { if (!this[kConnections]) { return; } @@ -618,7 +619,8 @@ Server.prototype.setTimeout = function setTimeout(msecs, callback) { return this; }; -Server.prototype[EE.captureRejectionSymbol] = function(err, event, ...args) { +Server.prototype[EE.captureRejectionSymbol] = +assignFunctionName(EE.captureRejectionSymbol, function(err, event, ...args) { switch (event) { case 'request': { const { 1: res } = args; @@ -639,7 +641,7 @@ Server.prototype[EE.captureRejectionSymbol] = function(err, event, ...args) { net.Server.prototype[SymbolFor('nodejs.rejection')] .apply(this, arguments); } -}; +}); function checkConnections() { if (this.headersTimeout === 0 && this.requestTimeout === 0) { diff --git a/lib/assert.js b/lib/assert.js index c0c4f026e68646..657ac6225d9833 100644 --- a/lib/assert.js +++ b/lib/assert.js @@ -54,7 +54,7 @@ const { isPromise, isRegExp, } = require('internal/util/types'); -const { isError, deprecate, emitExperimentalWarning } = require('internal/util'); +const { isError, deprecate } = require('internal/util'); const { innerOk } = require('internal/assert/utils'); const CallTracker = require('internal/assert/calltracker'); @@ -358,7 +358,6 @@ assert.partialDeepStrictEqual = function partialDeepStrictEqual( expected, message, ) { - emitExperimentalWarning('assert.partialDeepStrictEqual'); if (arguments.length < 2) { throw new ERR_MISSING_ARGS('actual', 'expected'); } diff --git a/lib/child_process.js b/lib/child_process.js index bb27670112c1ea..e848b3d5ee9b13 100644 --- a/lib/child_process.js +++ b/lib/child_process.js @@ -46,6 +46,7 @@ const { } = primordials; const { + assignFunctionName, convertToValidSignal, getSystemErrorName, kEmptyObject, @@ -236,7 +237,7 @@ function exec(command, options, callback) { } const customPromiseExecFunction = (orig) => { - return (...args) => { + return assignFunctionName(orig.name, function(...args) { const { promise, resolve, reject } = PromiseWithResolvers(); promise.child = orig(...args, (err, stdout, stderr) => { @@ -250,7 +251,7 @@ const customPromiseExecFunction = (orig) => { }); return promise; - }; + }); }; ObjectDefineProperty(exec, promisify.custom, { diff --git a/lib/dgram.js b/lib/dgram.js index 44f4e4298ad6fd..023941615214d0 100644 --- a/lib/dgram.js +++ b/lib/dgram.js @@ -800,7 +800,7 @@ Socket.prototype[SymbolAsyncDispose] = async function() { if (!this[kStateSymbol].handle) { return; } - return FunctionPrototypeCall(promisify(this.close), this); + await FunctionPrototypeCall(promisify(this.close), this); }; diff --git a/lib/eslint.config_partial.mjs b/lib/eslint.config_partial.mjs index c3ad0d705f0616..75f25f21901ff2 100644 --- a/lib/eslint.config_partial.mjs +++ b/lib/eslint.config_partial.mjs @@ -366,16 +366,6 @@ export default [ }, ], - // Stylistic rules. - '@stylistic/js/no-mixed-operators': [ - 'error', - { - groups: [ - ['&&', '||'], - ], - }, - ], - // Custom rules in tools/eslint-rules. 'node-core/alphabetize-errors': 'error', 'node-core/alphabetize-primordials': 'error', diff --git a/lib/events.js b/lib/events.js index 32ac2691bca0b8..48269193b37bcf 100644 --- a/lib/events.js +++ b/lib/events.js @@ -882,7 +882,7 @@ function listenerCount(type, listener) { /** * Returns an array listing the events for which * the emitter has registered listeners. - * @returns {any[]} + * @returns {(string | symbol)[]} */ EventEmitter.prototype.eventNames = function eventNames() { return this._eventsCount > 0 ? ReflectOwnKeys(this._events) : []; diff --git a/lib/fs.js b/lib/fs.js index c1df53f6aa9785..adfbbccc6e66c9 100644 --- a/lib/fs.js +++ b/lib/fs.js @@ -86,7 +86,6 @@ const { const { toPathIfFileURL } = require('internal/url'); const { customPromisifyArgs: kCustomPromisifyArgsSymbol, - emitExperimentalWarning, getLazy, kEmptyObject, promisify: { @@ -3186,7 +3185,6 @@ function createWriteStream(path, options) { const lazyGlob = getLazy(() => require('internal/fs/glob').Glob); function glob(pattern, options, callback) { - emitExperimentalWarning('glob'); if (typeof options === 'function') { callback = options; options = undefined; @@ -3209,7 +3207,6 @@ function glob(pattern, options, callback) { } function globSync(pattern, options) { - emitExperimentalWarning('globSync'); const Glob = lazyGlob(); return new Glob(pattern, options).globSync(); } diff --git a/lib/https.js b/lib/https.js index 21b40275ecb691..aaf5d22de66506 100644 --- a/lib/https.js +++ b/lib/https.js @@ -110,14 +110,14 @@ Server.prototype.closeIdleConnections = HttpServer.prototype.closeIdleConnection Server.prototype.setTimeout = HttpServer.prototype.setTimeout; -Server.prototype.close = function() { +Server.prototype.close = function close() { httpServerPreClose(this); ReflectApply(tls.Server.prototype.close, this, arguments); return this; }; Server.prototype[SymbolAsyncDispose] = async function() { - return FunctionPrototypeCall(promisify(this.close), this); + await FunctionPrototypeCall(promisify(this.close), this); }; /** diff --git a/lib/inspector.js b/lib/inspector.js index 106e03d68680a0..6b4255af811efd 100644 --- a/lib/inspector.js +++ b/lib/inspector.js @@ -217,6 +217,7 @@ const Network = { responseReceived: (params) => broadcastToFrontend('Network.responseReceived', params), loadingFinished: (params) => broadcastToFrontend('Network.loadingFinished', params), loadingFailed: (params) => broadcastToFrontend('Network.loadingFailed', params), + dataReceived: (params) => broadcastToFrontend('Network.dataReceived', params), }; module.exports = { diff --git a/lib/internal/async_local_storage/async_context_frame.js b/lib/internal/async_local_storage/async_context_frame.js index 72e1edf57ef0fe..e5131e53901739 100644 --- a/lib/internal/async_local_storage/async_context_frame.js +++ b/lib/internal/async_local_storage/async_context_frame.js @@ -1,6 +1,7 @@ 'use strict'; const { + ObjectIs, ReflectApply, } = primordials; @@ -26,12 +27,15 @@ class AsyncLocalStorage { } run(data, fn, ...args) { - const prior = AsyncContextFrame.current(); + const prior = this.getStore(); + if (ObjectIs(prior, data)) { + return ReflectApply(fn, null, args); + } this.enterWith(data); try { return ReflectApply(fn, null, args); } finally { - AsyncContextFrame.set(prior); + this.enterWith(prior); } } diff --git a/lib/internal/bootstrap/node.js b/lib/internal/bootstrap/node.js index 4fd535f730e638..dd9e3e58d72fb9 100644 --- a/lib/internal/bootstrap/node.js +++ b/lib/internal/bootstrap/node.js @@ -274,7 +274,7 @@ process.assert = deprecate( // TODO(joyeecheung): this property has not been well-maintained, should we // deprecate it in favor of a better API? -const { isDebugBuild, hasOpenSSL, hasInspector } = config; +const { isDebugBuild, hasOpenSSL, openSSLIsBoringSSL, hasInspector } = config; const features = { inspector: hasInspector, debug: isDebugBuild, @@ -284,6 +284,7 @@ const features = { tls_sni: hasOpenSSL, tls_ocsp: hasOpenSSL, tls: hasOpenSSL, + openssl_is_boringssl: openSSLIsBoringSSL, // This needs to be dynamic because --no-node-snapshot disables the // code cache even if the binary is built with embedded code cache. get cached_builtins() { diff --git a/lib/internal/buffer.js b/lib/internal/buffer.js index 20b22ad529385a..372f20c7bb2a44 100644 --- a/lib/internal/buffer.js +++ b/lib/internal/buffer.js @@ -1036,7 +1036,7 @@ function addBufferPrototypeMethods(proto) { proto.hexSlice = hexSlice; proto.ucs2Slice = ucs2Slice; proto.utf8Slice = utf8Slice; - proto.asciiWrite = function(string, offset = 0, length = this.byteLength) { + proto.asciiWrite = function asciiWrite(string, offset = 0, length = this.byteLength) { if (offset < 0 || offset > this.byteLength) { throw new ERR_BUFFER_OUT_OF_BOUNDS('offset'); } @@ -1047,7 +1047,7 @@ function addBufferPrototypeMethods(proto) { }; proto.base64Write = base64Write; proto.base64urlWrite = base64urlWrite; - proto.latin1Write = function(string, offset = 0, length = this.byteLength) { + proto.latin1Write = function latin1Write(string, offset = 0, length = this.byteLength) { if (offset < 0 || offset > this.byteLength) { throw new ERR_BUFFER_OUT_OF_BOUNDS('offset'); } @@ -1058,7 +1058,7 @@ function addBufferPrototypeMethods(proto) { }; proto.hexWrite = hexWrite; proto.ucs2Write = ucs2Write; - proto.utf8Write = function(string, offset = 0, length = this.byteLength) { + proto.utf8Write = function utf8Write(string, offset = 0, length = this.byteLength) { if (offset < 0 || offset > this.byteLength) { throw new ERR_BUFFER_OUT_OF_BOUNDS('offset'); } diff --git a/lib/internal/child_process.js b/lib/internal/child_process.js index ee41315d85e28e..35966d2d3c5d34 100644 --- a/lib/internal/child_process.js +++ b/lib/internal/child_process.js @@ -351,7 +351,7 @@ function closePendingHandle(target) { } -ChildProcess.prototype.spawn = function(options) { +ChildProcess.prototype.spawn = function spawn(options) { let i = 0; validateObject(options, 'options'); @@ -489,7 +489,7 @@ function onSpawnNT(self) { } -ChildProcess.prototype.kill = function(sig) { +ChildProcess.prototype.kill = function kill(sig) { const signal = sig === 0 ? sig : convertToValidSignal(sig === undefined ? 'SIGTERM' : sig); @@ -523,12 +523,12 @@ ChildProcess.prototype[SymbolDispose] = function() { }; -ChildProcess.prototype.ref = function() { +ChildProcess.prototype.ref = function ref() { if (this._handle) this._handle.ref(); }; -ChildProcess.prototype.unref = function() { +ChildProcess.prototype.unref = function unref() { if (this._handle) this._handle.unref(); }; diff --git a/lib/internal/errors.js b/lib/internal/errors.js index c4ce0500c2a852..2f15b9913f79c9 100644 --- a/lib/internal/errors.js +++ b/lib/internal/errors.js @@ -1342,7 +1342,12 @@ E('ERR_IMPORT_ATTRIBUTE_MISSING', E('ERR_IMPORT_ATTRIBUTE_TYPE_INCOMPATIBLE', 'Module "%s" is not of type "%s"', TypeError); E('ERR_IMPORT_ATTRIBUTE_UNSUPPORTED', - 'Import attribute "%s" with value "%s" is not supported', TypeError); + function error(attribute, value, url = undefined) { + if (url === undefined) { + return `Import attribute "${attribute}" with value "${value}" is not supported`; + } + return `Import attribute "${attribute}" with value "${value}" is not supported in ${url}`; + }, TypeError); E('ERR_INCOMPATIBLE_OPTION_PAIR', 'Option "%s" cannot be used in combination with option "%s"', TypeError, HideStackFramesError); E('ERR_INPUT_TYPE_NOT_ALLOWED', '--input-type can only be used with string ' + @@ -1806,6 +1811,8 @@ E('ERR_TRACE_EVENTS_CATEGORY_REQUIRED', 'At least one category is required', TypeError); E('ERR_TRACE_EVENTS_UNAVAILABLE', 'Trace events are unavailable', Error); +E('ERR_TRAILING_JUNK_AFTER_STREAM_END', 'Trailing junk found after the end of the compressed stream', TypeError); + // This should probably be a `RangeError`. E('ERR_TTY_INIT_FAILED', 'TTY initialization failed', SystemError); E('ERR_UNAVAILABLE_DURING_EXIT', 'Cannot call function in process exit ' + diff --git a/lib/internal/fs/cp/cp-sync.js b/lib/internal/fs/cp/cp-sync.js index 1e922b7805fc8c..382bd9b6b127e3 100644 --- a/lib/internal/fs/cp/cp-sync.js +++ b/lib/internal/fs/cp/cp-sync.js @@ -81,15 +81,12 @@ function getStats(src, dest, opts) { function onFile(srcStat, destStat, src, dest, opts) { if (!destStat) return copyFile(srcStat, src, dest, opts); - return mayCopyFile(srcStat, src, dest, opts); -} -// TODO(@anonrig): Move this function to C++. -function mayCopyFile(srcStat, src, dest, opts) { if (opts.force) { - unlinkSync(dest); - return copyFile(srcStat, src, dest, opts); - } else if (opts.errorOnExist) { + return fsBinding.cpSyncOverrideFile(src, dest, opts.mode, opts.preserveTimestamps); + } + + if (opts.errorOnExist) { throw new ERR_FS_CP_EEXIST({ message: `${dest} already exists`, path: dest, @@ -136,18 +133,27 @@ function setDestTimestamps(src, dest) { // TODO(@anonrig): Move this function to C++. function onDir(srcStat, destStat, src, dest, opts) { - if (!destStat) return mkDirAndCopy(srcStat.mode, src, dest, opts); + if (!destStat) return copyDir(src, dest, opts, true, srcStat.mode); return copyDir(src, dest, opts); } -function mkDirAndCopy(srcMode, src, dest, opts) { - mkdirSync(dest); - copyDir(src, dest, opts); - return setDestMode(dest, srcMode); -} +function copyDir(src, dest, opts, mkDir, srcMode) { + if (!opts.filter) { + // The caller didn't provide a js filter function, in this case + // we can run the whole function faster in C++ + // TODO(dario-piotrowicz): look into making cpSyncCopyDir also accept the potential filter function + return fsBinding.cpSyncCopyDir(src, dest, + opts.force, + opts.dereference, + opts.errorOnExist, + opts.verbatimSymlinks, + opts.preserveTimestamps); + } + + if (mkDir) { + mkdirSync(dest); + } -// TODO(@anonrig): Move this function to C++. -function copyDir(src, dest, opts) { const dir = opendirSync(src); try { @@ -172,6 +178,10 @@ function copyDir(src, dest, opts) { } } finally { dir.closeSync(); + + if (srcMode !== undefined) { + setDestMode(dest, srcMode); + } } } diff --git a/lib/internal/fs/dir.js b/lib/internal/fs/dir.js index f227b51af03669..7cc1477abca5ee 100644 --- a/lib/internal/fs/dir.js +++ b/lib/internal/fs/dir.js @@ -4,7 +4,7 @@ const { ArrayPrototypePush, ArrayPrototypeShift, FunctionPrototypeBind, - ObjectDefineProperty, + ObjectDefineProperties, PromiseReject, SymbolAsyncIterator, } = primordials; @@ -21,7 +21,12 @@ const { } = require('internal/errors'); const { FSReqCallback } = binding; -const internalUtil = require('internal/util'); +const { + assignFunctionName, + promisify, + SymbolAsyncDispose, + SymbolDispose, +} = require('internal/util'); const { getDirent, getOptions, @@ -57,9 +62,9 @@ class Dir { validateUint32(this.#options.bufferSize, 'options.bufferSize', true); this.#readPromisified = FunctionPrototypeBind( - internalUtil.promisify(this.#readImpl), this, false); + promisify(this.#readImpl), this, false); this.#closePromisified = FunctionPrototypeBind( - internalUtil.promisify(this.close), this); + promisify(this.close), this); } get path() { @@ -94,7 +99,7 @@ class Dir { } read(callback) { - return this.#readImpl(true, callback); + return arguments.length === 0 ? this.#readPromisified() : this.#readImpl(true, callback); } #readImpl(maybeSync, callback) { @@ -293,12 +298,31 @@ class Dir { } } -ObjectDefineProperty(Dir.prototype, SymbolAsyncIterator, { - __proto__: null, - value: Dir.prototype.entries, +const nonEnumerableDescriptor = { enumerable: false, writable: true, configurable: true, +}; +ObjectDefineProperties(Dir.prototype, { + [SymbolDispose]: { + __proto__: null, + ...nonEnumerableDescriptor, + value: assignFunctionName(SymbolDispose, function() { + this.closeSync(); + }), + }, + [SymbolAsyncDispose]: { + __proto__: null, + ...nonEnumerableDescriptor, + value: assignFunctionName(SymbolAsyncDispose, function() { + this.close(); + }), + }, + [SymbolAsyncIterator]: { + __proto__: null, + ...nonEnumerableDescriptor, + value: Dir.prototype.entries, + }, }); function opendir(path, options, callback) { diff --git a/lib/internal/fs/glob.js b/lib/internal/fs/glob.js index 5e6b4828ceb02b..b5966549045b79 100644 --- a/lib/internal/fs/glob.js +++ b/lib/internal/fs/glob.js @@ -38,6 +38,7 @@ const { hideStackFrames, } = require('internal/errors'); const assert = require('internal/assert'); +const { toPathIfFileURL } = require('internal/url'); let minimatch; function lazyMinimatch() { @@ -268,7 +269,7 @@ class Glob { constructor(pattern, options = kEmptyObject) { validateObject(options, 'options'); const { exclude, cwd, withFileTypes } = options; - this.#root = cwd ?? '.'; + this.#root = toPathIfFileURL(cwd) ?? '.'; this.#withFileTypes = !!withFileTypes; if (exclude != null) { validateStringArrayOrFunction(exclude, 'options.exclude'); diff --git a/lib/internal/fs/promises.js b/lib/internal/fs/promises.js index ebf9f3792325ea..e43fb2a3daa29d 100644 --- a/lib/internal/fs/promises.js +++ b/lib/internal/fs/promises.js @@ -84,14 +84,12 @@ const { validateEncoding, validateInteger, validateObject, - validateString, kValidateObjectAllowNullable, } = require('internal/validators'); const pathModule = require('path'); const { isAbsolute } = pathModule; const { toPathIfFileURL } = require('internal/url'); const { - emitExperimentalWarning, getLazy, kEmptyObject, lazyDOMException, @@ -273,15 +271,16 @@ class FileHandle extends EventEmitter { }; async [SymbolAsyncDispose]() { - return this.close(); + await this.close(); } /** * @typedef {import('../webstreams/readablestream').ReadableStream * } ReadableStream + * @param {{ type?: 'bytes', autoClose?: boolean }} [options] * @returns {ReadableStream} */ - readableWebStream(options = { __proto__: null, type: 'bytes' }) { + readableWebStream(options = kEmptyObject) { if (this[kFd] === -1) throw new ERR_INVALID_STATE('The FileHandle is closed'); if (this[kClosePromise]) @@ -290,10 +289,15 @@ class FileHandle extends EventEmitter { throw new ERR_INVALID_STATE('The FileHandle is locked'); this[kLocked] = true; - if (options.type !== undefined) { - validateString(options.type, 'options.type'); - } - if (options.type !== 'bytes') { + validateObject(options, 'options'); + const { + type = 'bytes', + autoClose = false, + } = options; + + validateBoolean(autoClose, 'options.autoClose'); + + if (type !== 'bytes') { process.emitWarning( 'A non-"bytes" options.type has no effect. A byte-oriented steam is ' + 'always created.', @@ -301,9 +305,11 @@ class FileHandle extends EventEmitter { ); } - const readFn = FunctionPrototypeBind(this.read, this); - const ondone = FunctionPrototypeBind(this[kUnref], this); + const ondone = async () => { + this[kUnref](); + if (autoClose) await this.close(); + }; const ReadableStream = lazyReadableStream(); const readable = new ReadableStream({ @@ -315,15 +321,15 @@ class FileHandle extends EventEmitter { const { bytesRead } = await readFn(view, view.byteOffset, view.byteLength); if (bytesRead === 0) { - ondone(); controller.close(); + await ondone(); } controller.byobRequest.respond(bytesRead); }, - cancel() { - ondone(); + async cancel() { + await ondone(); }, }); @@ -1260,7 +1266,6 @@ async function* _watch(filename, options = kEmptyObject) { const lazyGlob = getLazy(() => require('internal/fs/glob').Glob); async function* glob(pattern, options) { - emitExperimentalWarning('glob'); const Glob = lazyGlob(); yield* new Glob(pattern, options).glob(); } diff --git a/lib/internal/http2/core.js b/lib/internal/http2/core.js index cf7b06d987c0fe..c15852ca4f1975 100644 --- a/lib/internal/http2/core.js +++ b/lib/internal/http2/core.js @@ -9,7 +9,6 @@ const { ObjectDefineProperty, ObjectEntries, ObjectHasOwn, - ObjectKeys, Promise, Proxy, ReflectApply, @@ -24,6 +23,7 @@ const { } = primordials; const { + assignFunctionName, assertCrypto, customInspectSymbol: kInspect, kEmptyObject, @@ -46,10 +46,7 @@ const { Duplex } = require('stream'); const tls = require('tls'); const { setImmediate, setTimeout, clearTimeout } = require('timers'); -const { - kIncomingMessage, - _checkIsHttpToken: checkIsHttpToken, -} = require('_http_common'); +const { kIncomingMessage } = require('_http_common'); const { kServerResponse, Server: HttpServer, httpServerPreClose, setupConnectionsTracking } = require('_http_server'); const JSStreamSocket = require('internal/js_stream_socket'); @@ -68,9 +65,6 @@ const { codes: { ERR_HTTP2_ALTSVC_INVALID_ORIGIN, ERR_HTTP2_ALTSVC_LENGTH, - ERR_HTTP2_CONNECT_AUTHORITY, - ERR_HTTP2_CONNECT_PATH, - ERR_HTTP2_CONNECT_SCHEME, ERR_HTTP2_GOAWAY_SESSION, ERR_HTTP2_HEADERS_AFTER_RESPOND, ERR_HTTP2_HEADERS_SENT, @@ -108,7 +102,6 @@ const { ERR_INVALID_ARG_TYPE, ERR_INVALID_ARG_VALUE, ERR_INVALID_CHAR, - ERR_INVALID_HTTP_TOKEN, ERR_OUT_OF_RANGE, ERR_SOCKET_CLOSED, }, @@ -137,23 +130,26 @@ const { const { assertIsObject, assertIsArray, - assertValidPseudoHeader, assertValidPseudoHeaderResponse, assertValidPseudoHeaderTrailer, assertWithinRange, + buildNgHeaderString, getAuthority, getDefaultSettings, getSessionState, getSettings, getStreamState, isPayloadMeaningless, + kAuthority, kSensitiveHeaders, kSocket, kRequest, + kProtocol, kProxySocket, - mapToHeaders, MAX_ADDITIONAL_SETTINGS, NghttpError, + prepareRequestHeadersArray, + prepareRequestHeadersObject, remoteCustomSettingsToBuffer, sessionName, toHeaderObject, @@ -187,6 +183,18 @@ const { UV_EOF } = internalBinding('uv'); const { StreamPipe } = internalBinding('stream_pipe'); const { _connectionListener: httpConnectionListener } = http; + +const dc = require('diagnostics_channel'); +const onClientStreamCreatedChannel = dc.channel('http2.client.stream.created'); +const onClientStreamStartChannel = dc.channel('http2.client.stream.start'); +const onClientStreamErrorChannel = dc.channel('http2.client.stream.error'); +const onClientStreamFinishChannel = dc.channel('http2.client.stream.finish'); +const onClientStreamCloseChannel = dc.channel('http2.client.stream.close'); +const onServerStreamCreatedChannel = dc.channel('http2.server.stream.created'); +const onServerStreamStartChannel = dc.channel('http2.server.stream.start'); +const onServerStreamErrorChannel = dc.channel('http2.server.stream.error'); +const onServerStreamFinishChannel = dc.channel('http2.server.stream.finish'); + let debug = require('internal/util/debuglog').debuglog('http2', (fn) => { debug = fn; }); @@ -229,7 +237,6 @@ const NETServer = net.Server; const TLSServer = tls.Server; const kAlpnProtocol = Symbol('alpnProtocol'); -const kAuthority = Symbol('authority'); const kEncrypted = Symbol('encrypted'); const kID = Symbol('id'); const kInit = Symbol('init'); @@ -241,10 +248,8 @@ const kOwner = owner_symbol; const kOrigin = Symbol('origin'); const kPendingRequestCalls = Symbol('kPendingRequestCalls'); const kProceed = Symbol('proceed'); -const kProtocol = Symbol('protocol'); const kRemoteSettings = Symbol('remote-settings'); const kRequestAsyncResource = Symbol('requestAsyncResource'); -const kSelectPadding = Symbol('select-padding'); const kSentHeaders = Symbol('sent-headers'); const kSentTrailers = Symbol('sent-trailers'); const kServer = Symbol('server'); @@ -285,7 +290,6 @@ const { HTTP2_HEADER_DATE, HTTP2_HEADER_METHOD, HTTP2_HEADER_PATH, - HTTP2_HEADER_PROTOCOL, HTTP2_HEADER_SCHEME, HTTP2_HEADER_STATUS, HTTP2_HEADER_CONTENT_LENGTH, @@ -300,7 +304,6 @@ const { HTTP2_METHOD_GET, HTTP2_METHOD_HEAD, - HTTP2_METHOD_CONNECT, HTTP_STATUS_CONTINUE, HTTP_STATUS_RESET_CONTENT, @@ -366,6 +369,18 @@ function onSessionHeaders(handle, id, cat, flags, headers, sensitiveHeaders) { if (type === NGHTTP2_SESSION_SERVER) { // eslint-disable-next-line no-use-before-define stream = new ServerHttp2Stream(session, handle, id, {}, obj); + if (onServerStreamCreatedChannel.hasSubscribers) { + onServerStreamCreatedChannel.publish({ + stream, + headers: obj, + }); + } + if (onServerStreamStartChannel.hasSubscribers) { + onServerStreamStartChannel.publish({ + stream, + headers: obj, + }); + } if (endOfStream) { stream.push(null); } @@ -378,6 +393,18 @@ function onSessionHeaders(handle, id, cat, flags, headers, sensitiveHeaders) { } else { // eslint-disable-next-line no-use-before-define stream = new ClientHttp2Stream(session, handle, id, {}); + if (onClientStreamCreatedChannel.hasSubscribers) { + onClientStreamCreatedChannel.publish({ + stream, + headers: obj, + }); + } + if (onClientStreamStartChannel.hasSubscribers) { + onClientStreamStartChannel.publish({ + stream, + headers: obj, + }); + } if (endOfStream) { stream.push(null); } @@ -416,6 +443,15 @@ function onSessionHeaders(handle, id, cat, flags, headers, sensitiveHeaders) { reqAsync.runInAsyncScope(process.nextTick, null, emit, stream, event, obj, flags, headers); else process.nextTick(emit, stream, event, obj, flags, headers); + if ((event === 'response' || + event === 'push') && + onClientStreamFinishChannel.hasSubscribers) { + onClientStreamFinishChannel.publish({ + stream, + headers: obj, + flags: flags, + }); + } } if (endOfStream) { stream.push(null); @@ -714,7 +750,7 @@ function onGoawayData(code, lastStreamID, buf) { // When a ClientHttp2Session is first created, the socket may not yet be // connected. If request() is called during this time, the actual request // will be deferred until the socket is ready to go. -function requestOnConnect(headers, options) { +function requestOnConnect(headersList, headersParam, options) { const session = this[kSession]; // At this point, the stream should have already been destroyed during @@ -741,7 +777,7 @@ function requestOnConnect(headers, options) { // `ret` will be either the reserved stream ID (if positive) // or an error code (if negative) - const ret = session[kHandle].request(headers, + const ret = session[kHandle].request(headersList, streamOptions, options.parent | 0, options.weight | 0, @@ -773,6 +809,12 @@ function requestOnConnect(headers, options) { return; } this[kInit](ret.id(), ret); + if (onClientStreamStartChannel.hasSubscribers) { + onClientStreamStartChannel.publish({ + stream: this, + headers: headersParam, + }); + } } // Validates that priority options are correct, specifically: @@ -1065,8 +1107,6 @@ function setupHandle(socket, type, options) { const handle = new binding.Http2Session(type); handle[kOwner] = this; - if (typeof options.selectPadding === 'function') - this[kSelectPadding] = options.selectPadding; handle.consume(socket._handle); handle.ongracefulclosecomplete = this[kMaybeDestroy].bind(this, null); @@ -1759,7 +1799,7 @@ class ClientHttp2Session extends Http2Session { // Submits a new HTTP2 request to the connected peer. Returns the // associated Http2Stream instance. - request(headers, options) { + request(headersParam, options) { debugSessionObj(this, 'initiating request'); if (this.destroyed) @@ -1770,62 +1810,61 @@ class ClientHttp2Session extends Http2Session { this[kUpdateTimer](); - if (headers !== null && headers !== undefined) { - const keys = ObjectKeys(headers); - for (let i = 0; i < keys.length; i++) { - const header = keys[i]; - if (header[0] === ':') { - assertValidPseudoHeader(header); - } else if (header && !checkIsHttpToken(header)) - this.destroy(new ERR_INVALID_HTTP_TOKEN('Header name', header)); - } + let headersList; + let headersObject; + let scheme; + let authority; + let method; + + if (ArrayIsArray(headersParam)) { + ({ + headersList, + scheme, + authority, + method, + } = prepareRequestHeadersArray(headersParam, this)); + } else if (!!headersParam && typeof headersParam === 'object') { + ({ + headersObject, + headersList, + scheme, + authority, + method, + } = prepareRequestHeadersObject(headersParam, this)); + } else if (headersParam === undefined) { + ({ + headersObject, + headersList, + scheme, + authority, + method, + } = prepareRequestHeadersObject({}, this)); + } else { + throw new ERR_INVALID_ARG_TYPE.HideStackFramesError( + 'headers', + ['Object', 'Array'], + headersParam, + ); } - assertIsObject(headers, 'headers'); assertIsObject(options, 'options'); - - headers = ObjectAssign({ __proto__: null }, headers); options = { ...options }; - if (headers[HTTP2_HEADER_METHOD] === undefined) - headers[HTTP2_HEADER_METHOD] = HTTP2_METHOD_GET; - - const connect = headers[HTTP2_HEADER_METHOD] === HTTP2_METHOD_CONNECT; - - if (!connect || headers[HTTP2_HEADER_PROTOCOL] !== undefined) { - if (getAuthority(headers) === undefined) - headers[HTTP2_HEADER_AUTHORITY] = this[kAuthority]; - if (headers[HTTP2_HEADER_SCHEME] === undefined) - headers[HTTP2_HEADER_SCHEME] = this[kProtocol].slice(0, -1); - if (headers[HTTP2_HEADER_PATH] === undefined) - headers[HTTP2_HEADER_PATH] = '/'; - } else { - if (headers[HTTP2_HEADER_AUTHORITY] === undefined) - throw new ERR_HTTP2_CONNECT_AUTHORITY(); - if (headers[HTTP2_HEADER_SCHEME] !== undefined) - throw new ERR_HTTP2_CONNECT_SCHEME(); - if (headers[HTTP2_HEADER_PATH] !== undefined) - throw new ERR_HTTP2_CONNECT_PATH(); - } - setAndValidatePriorityOptions(options); if (options.endStream === undefined) { // For some methods, we know that a payload is meaningless, so end the // stream by default if the user has not specifically indicated a // preference. - options.endStream = isPayloadMeaningless(headers[HTTP2_HEADER_METHOD]); + options.endStream = isPayloadMeaningless(method); } else { validateBoolean(options.endStream, 'options.endStream'); } - const headersList = mapToHeaders(headers); - // eslint-disable-next-line no-use-before-define const stream = new ClientHttp2Stream(this, undefined, undefined, {}); - stream[kSentHeaders] = headers; - stream[kOrigin] = `${headers[HTTP2_HEADER_SCHEME]}://` + - `${getAuthority(headers)}`; + stream[kSentHeaders] = headersObject; // N.b. Only set for object headers, not raw headers + stream[kOrigin] = `${scheme}://${authority}`; const reqAsync = new AsyncResource('PendingRequest'); stream[kRequestAsyncResource] = reqAsync; @@ -1850,7 +1889,7 @@ class ClientHttp2Session extends Http2Session { } } - const onConnect = reqAsync.bind(requestOnConnect.bind(stream, headersList, options)); + const onConnect = reqAsync.bind(requestOnConnect.bind(stream, headersList, headersParam, options)); if (this.connecting) { if (this[kPendingRequestCalls] !== null) { this[kPendingRequestCalls].push(onConnect); @@ -1864,6 +1903,14 @@ class ClientHttp2Session extends Http2Session { } else { onConnect(); } + + if (onClientStreamCreatedChannel.hasSubscribers) { + onClientStreamCreatedChannel.publish({ + stream, + headers: headersParam, + }); + } + return stream; } } @@ -1938,6 +1985,7 @@ const kSubmitRstStream = 1; const kForceRstStream = 2; function closeStream(stream, code, rstStreamStatus = kSubmitRstStream) { + const type = stream[kSession][kType]; const state = stream[kState]; state.flags |= STREAM_FLAGS_CLOSED; state.rstCode = code; @@ -1968,6 +2016,11 @@ function closeStream(stream, code, rstStreamStatus = kSubmitRstStream) { else stream.once('finish', finishFn); } + + if (type === NGHTTP2_SESSION_CLIENT && + onClientStreamCloseChannel.hasSubscribers) { + onClientStreamCloseChannel.publish({ stream }); + } } function finishCloseStream(code) { @@ -2287,7 +2340,7 @@ class Http2Stream extends Duplex { this[kUpdateTimer](); - const headersList = mapToHeaders(headers, assertValidPseudoHeaderTrailer); + const headersList = buildNgHeaderString(headers, assertValidPseudoHeaderTrailer); this[kSentTrailers] = headers; // Send the trailers in setImmediate so we don't do it on nghttp2 stack. @@ -2394,6 +2447,21 @@ class Http2Stream extends Duplex { setImmediate(() => { session[kMaybeDestroy](); }); + if (err) { + if (session[kType] === NGHTTP2_SESSION_CLIENT) { + if (onClientStreamErrorChannel.hasSubscribers) { + onClientStreamErrorChannel.publish({ + stream: this, + error: err, + }); + } + } else if (onServerStreamErrorChannel.hasSubscribers) { + onServerStreamErrorChannel.publish({ + stream: this, + error: err, + }); + } + } callback(err); } // The Http2Stream can be destroyed if it has closed and if the readable @@ -2520,7 +2588,7 @@ function processRespondWithFD(self, fd, headers, offset = 0, length = -1, let headersList; try { - headersList = mapToHeaders(headers, assertValidPseudoHeaderResponse); + headersList = buildNgHeaderString(headers, assertValidPseudoHeaderResponse); } catch (err) { self.destroy(err); return; @@ -2744,7 +2812,7 @@ class ServerHttp2Stream extends Http2Stream { if (headers[HTTP2_HEADER_METHOD] === HTTP2_METHOD_HEAD) headRequest = options.endStream = true; - const headersList = mapToHeaders(headers); + const headersList = buildNgHeaderString(headers); const streamOptions = options.endStream ? STREAM_OPTION_EMPTY_PAYLOAD : 0; @@ -2778,7 +2846,23 @@ class ServerHttp2Stream extends Http2Stream { if (headRequest) stream[kState].flags |= STREAM_FLAGS_HEAD_REQUEST; - process.nextTick(callback, null, stream, headers, 0); + process.nextTick(() => { + if (onServerStreamStartChannel.hasSubscribers) { + onServerStreamStartChannel.publish({ + stream, + headers, + }); + } + + callback(null, stream, headers, 0); + }); + + if (onServerStreamCreatedChannel.hasSubscribers) { + onServerStreamCreatedChannel.publish({ + stream, + headers, + }); + } } // Initiate a response on this Http2Stream @@ -2808,7 +2892,7 @@ class ServerHttp2Stream extends Http2Stream { } headers = processHeaders(headers, options); - const headersList = mapToHeaders(headers, assertValidPseudoHeaderResponse); + const headersList = buildNgHeaderString(headers, assertValidPseudoHeaderResponse); this[kSentHeaders] = headers; state.flags |= STREAM_FLAGS_HEADERS_SENT; @@ -2826,8 +2910,17 @@ class ServerHttp2Stream extends Http2Stream { } const ret = this[kHandle].respond(headersList, streamOptions); - if (ret < 0) + if (ret < 0) { this.destroy(new NghttpError(ret)); + } else if (onServerStreamFinishChannel.hasSubscribers) { + // No point in running this if the respond() call above fails because + // that would mean that it is an invalid call. + onServerStreamFinishChannel.publish({ + stream: this, + headers, + flags: state.flags, + }); + } } // Initiate a response using an open FD. Note that there are fewer @@ -2976,7 +3069,7 @@ class ServerHttp2Stream extends Http2Stream { this[kUpdateTimer](); - const headersList = mapToHeaders(headers, assertValidPseudoHeaderResponse); + const headersList = buildNgHeaderString(headers, assertValidPseudoHeaderResponse); if (!this[kInfoHeaders]) this[kInfoHeaders] = [headers]; else @@ -3249,7 +3342,7 @@ class Http2Server extends NETServer { } async [SymbolAsyncDispose]() { - return promisify(super.close).call(this); + await promisify(super.close).call(this); } } @@ -3376,7 +3469,7 @@ function connect(authority, options, listener) { // Support util.promisify ObjectDefineProperty(connect, promisify.custom, { __proto__: null, - value: (authority, options) => { + value: assignFunctionName('connect', function(authority, options) { return new Promise((resolve, reject) => { const server = connect(authority, options, () => { server.removeListener('error', reject); @@ -3385,7 +3478,7 @@ ObjectDefineProperty(connect, promisify.custom, { server.once('error', reject); }); - }, + }), }); function createSecureServer(options, handler) { diff --git a/lib/internal/http2/util.js b/lib/internal/http2/util.js index d1fea4a49f0a18..396623d3b9d06f 100644 --- a/lib/internal/http2/util.js +++ b/lib/internal/http2/util.js @@ -6,6 +6,7 @@ const { MathMax, Number, NumberIsNaN, + ObjectAssign, ObjectKeys, SafeSet, String, @@ -13,9 +14,16 @@ const { Symbol, } = primordials; +const { + _checkIsHttpToken: checkIsHttpToken, +} = require('_http_common'); + const binding = internalBinding('http2'); const { codes: { + ERR_HTTP2_CONNECT_AUTHORITY, + ERR_HTTP2_CONNECT_PATH, + ERR_HTTP2_CONNECT_SCHEME, ERR_HTTP2_HEADER_SINGLE_VALUE, ERR_HTTP2_INVALID_CONNECTION_HEADERS, ERR_HTTP2_INVALID_PSEUDOHEADER: { HideStackFramesError: ERR_HTTP2_INVALID_PSEUDOHEADER }, @@ -29,8 +37,10 @@ const { kIsNodeError, } = require('internal/errors'); +const kAuthority = Symbol('authority'); const kSensitiveHeaders = Symbol('sensitiveHeaders'); const kSocket = Symbol('socket'); +const kProtocol = Symbol('protocol'); const kProxySocket = Symbol('proxySocket'); const kRequest = Symbol('request'); @@ -91,6 +101,7 @@ const { HTTP2_HEADER_KEEP_ALIVE, HTTP2_HEADER_PROXY_CONNECTION, + HTTP2_METHOD_CONNECT, HTTP2_METHOD_DELETE, HTTP2_METHOD_GET, HTTP2_METHOD_HEAD, @@ -218,7 +229,8 @@ const IDX_OPTIONS_MAX_SESSION_MEMORY = 8; const IDX_OPTIONS_MAX_SETTINGS = 9; const IDX_OPTIONS_STREAM_RESET_RATE = 10; const IDX_OPTIONS_STREAM_RESET_BURST = 11; -const IDX_OPTIONS_FLAGS = 12; +const IDX_OPTIONS_STRICT_HTTP_FIELD_WHITESPACE_VALIDATION = 12; +const IDX_OPTIONS_FLAGS = 13; function updateOptionsBuffer(options) { let flags = 0; @@ -282,6 +294,13 @@ function updateOptionsBuffer(options) { optionsBuffer[IDX_OPTIONS_STREAM_RESET_BURST] = MathMax(1, options.streamResetBurst); } + + if (typeof options.strictFieldWhitespaceValidation === 'boolean') { + flags |= (1 << IDX_OPTIONS_STRICT_HTTP_FIELD_WHITESPACE_VALIDATION); + optionsBuffer[IDX_OPTIONS_STRICT_HTTP_FIELD_WHITESPACE_VALIDATION] = + options.strictFieldWhitespaceValidation === true ? 0 : 1; + } + optionsBuffer[IDX_OPTIONS_FLAGS] = flags; } @@ -593,35 +612,155 @@ const assertValidPseudoHeaderTrailer = hideStackFrames((key) => { throw new ERR_HTTP2_INVALID_PSEUDOHEADER(key); }); +/** + * Takes a request headers array, validates it and sets defaults, and returns + * the resulting headers in NgHeaders string list format. + */ +function prepareRequestHeadersArray(headers, session) { + let method; + let scheme; + let authority; + let path; + let protocol; + + // Extract the key psuedo header values from the headers array + for (let i = 0; i < headers.length; i += 2) { + if (headers[i][0] !== ':') { + continue; + } + + const header = headers[i].toLowerCase(); + const value = headers[i + 1]; + + if (header === HTTP2_HEADER_METHOD) { + method = value; + } else if (header === HTTP2_HEADER_SCHEME) { + scheme = value; + } else if (header === HTTP2_HEADER_AUTHORITY) { + authority = value; + } else if (header === HTTP2_HEADER_PATH) { + path = value; + } else if (header === HTTP2_HEADER_PROTOCOL) { + protocol = value; + } + } + + // We then build an array of any missing pseudo headers, to prepend + // default values to the given header array: + const additionalPsuedoHeaders = []; + + if (method === undefined) { + method = HTTP2_METHOD_GET; + additionalPsuedoHeaders.push(HTTP2_HEADER_METHOD, method); + } + + const connect = method === HTTP2_METHOD_CONNECT; + + if (!connect || protocol !== undefined) { + if (authority === undefined && headers[HTTP2_HEADER_HOST] === undefined) { + authority = session[kAuthority]; + additionalPsuedoHeaders.push(HTTP2_HEADER_AUTHORITY, authority); + } + if (scheme === undefined) { + scheme = session[kProtocol].slice(0, -1); + additionalPsuedoHeaders.push(HTTP2_HEADER_SCHEME, scheme); + } + if (path === undefined) { + additionalPsuedoHeaders.push(HTTP2_HEADER_PATH, '/'); + } + } else { + if (authority === undefined) + throw new ERR_HTTP2_CONNECT_AUTHORITY(); + if (scheme !== undefined) + throw new ERR_HTTP2_CONNECT_SCHEME(); + if (path !== undefined) + throw new ERR_HTTP2_CONNECT_PATH(); + } + + const headersList = buildNgHeaderString( + additionalPsuedoHeaders.length ? + additionalPsuedoHeaders.concat(headers) : + headers, + assertValidPseudoHeader, + headers[kSensitiveHeaders], + ); + + return { + headersList, + scheme, + authority: authority ?? headers[HTTP2_HEADER_HOST], + method, + }; +} + +/** + * Takes a request headers object, validates it and sets defaults, and returns + * the resulting headers in object format and NgHeaders string list format. + */ +function prepareRequestHeadersObject(headers, session) { + const headersObject = ObjectAssign({ __proto__: null }, headers); + + if (headersObject[HTTP2_HEADER_METHOD] === undefined) { + headersObject[HTTP2_HEADER_METHOD] = HTTP2_METHOD_GET; + } + + const connect = headersObject[HTTP2_HEADER_METHOD] === HTTP2_METHOD_CONNECT; + + if (!connect || headersObject[HTTP2_HEADER_PROTOCOL] !== undefined) { + if (getAuthority(headersObject) === undefined) + headersObject[HTTP2_HEADER_AUTHORITY] = session[kAuthority]; + if (headersObject[HTTP2_HEADER_SCHEME] === undefined) + headersObject[HTTP2_HEADER_SCHEME] = session[kProtocol].slice(0, -1); + if (headersObject[HTTP2_HEADER_PATH] === undefined) + headersObject[HTTP2_HEADER_PATH] = '/'; + } else { + if (headersObject[HTTP2_HEADER_AUTHORITY] === undefined) + throw new ERR_HTTP2_CONNECT_AUTHORITY(); + if (headersObject[HTTP2_HEADER_SCHEME] !== undefined) + throw new ERR_HTTP2_CONNECT_SCHEME(); + if (headersObject[HTTP2_HEADER_PATH] !== undefined) + throw new ERR_HTTP2_CONNECT_PATH(); + } + + const headersList = buildNgHeaderString(headersObject); + + return { + headersObject, + headersList, + scheme: headersObject[HTTP2_HEADER_SCHEME], + authority: getAuthority(headersObject), + method: headersObject[HTTP2_HEADER_METHOD], + }; +} + const emptyArray = []; const kNeverIndexFlag = StringFromCharCode(NGHTTP2_NV_FLAG_NO_INDEX); const kNoHeaderFlags = StringFromCharCode(NGHTTP2_NV_FLAG_NONE); -function mapToHeaders(map, - assertValuePseudoHeader = assertValidPseudoHeader) { + +/** + * Builds an NgHeader string + header count value, validating the header key + * format, rejecting illegal header configurations, and marking sensitive headers + * that should not be indexed en route. This takes either a flat map of + * raw headers ([k1, v1, k2, v2]) or a header object ({ k1: v1, k2: [v2, v3] }). + */ +function buildNgHeaderString(arrayOrMap, + assertValuePseudoHeader = assertValidPseudoHeader, + sensitiveHeaders = arrayOrMap[kSensitiveHeaders]) { let headers = ''; let pseudoHeaders = ''; let count = 0; - const keys = ObjectKeys(map); + const singles = new SafeSet(); - let i, j; - let isArray; - let key; - let value; - let isSingleValueHeader; - let err; - const neverIndex = (map[kSensitiveHeaders] || emptyArray).map((v) => v.toLowerCase()); - for (i = 0; i < keys.length; ++i) { - key = keys[i]; - value = map[key]; - if (value === undefined || key === '') - continue; + const neverIndex = (sensitiveHeaders || emptyArray).map((v) => v.toLowerCase()); + + function processHeader(key, value) { key = key.toLowerCase(); - isSingleValueHeader = kSingleValueHeaders.has(key); - isArray = ArrayIsArray(value); + const isSingleValueHeader = kSingleValueHeaders.has(key); + let isArray = ArrayIsArray(value); if (isArray) { switch (value.length) { case 0: - continue; + return; case 1: value = String(value[0]); isArray = false; @@ -642,31 +781,50 @@ function mapToHeaders(map, kNeverIndexFlag : kNoHeaderFlags; if (key[0] === ':') { - err = assertValuePseudoHeader(key); + const err = assertValuePseudoHeader(key); if (err !== undefined) throw err; pseudoHeaders += `${key}\0${value}\0${flags}`; count++; - continue; + return; } - if (key.includes(' ')) { + if (!checkIsHttpToken(key)) { throw new ERR_INVALID_HTTP_TOKEN('Header name', key); } if (isIllegalConnectionSpecificHeader(key, value)) { throw new ERR_HTTP2_INVALID_CONNECTION_HEADERS(key); } if (isArray) { - for (j = 0; j < value.length; ++j) { + for (let j = 0; j < value.length; ++j) { const val = String(value[j]); headers += `${key}\0${val}\0${flags}`; } count += value.length; - continue; + return; } headers += `${key}\0${value}\0${flags}`; count++; } + if (ArrayIsArray(arrayOrMap)) { + for (let i = 0; i < arrayOrMap.length; i += 2) { + const key = arrayOrMap[i]; + const value = arrayOrMap[i + 1]; + if (value === undefined || key === '') + continue; + processHeader(key, value); + } + } else { + const keys = ObjectKeys(arrayOrMap); + for (let i = 0; i < keys.length; ++i) { + const key = keys[i]; + const value = arrayOrMap[key]; + if (value === undefined || key === '') + continue; + processHeader(key, value); + } + } + return [pseudoHeaders + headers, count]; } @@ -793,19 +951,23 @@ module.exports = { assertValidPseudoHeaderResponse, assertValidPseudoHeaderTrailer, assertWithinRange, + buildNgHeaderString, getAuthority, getDefaultSettings, getSessionState, getSettings, getStreamState, isPayloadMeaningless, + kAuthority, kSensitiveHeaders, kSocket, + kProtocol, kProxySocket, kRequest, - mapToHeaders, MAX_ADDITIONAL_SETTINGS, NghttpError, + prepareRequestHeadersArray, + prepareRequestHeadersObject, remoteCustomSettingsToBuffer, sessionName, toHeaderObject, diff --git a/lib/internal/inspector/network_http.js b/lib/internal/inspector/network_http.js index 00b671cc4f8e7a..24c3598fd61763 100644 --- a/lib/internal/inspector/network_http.js +++ b/lib/internal/inspector/network_http.js @@ -16,6 +16,7 @@ const { } = require('internal/inspector/network'); const dc = require('diagnostics_channel'); const { Network } = require('inspector'); +const { MIMEType } = require('internal/mime'); const kRequestUrl = Symbol('kRequestUrl'); @@ -93,6 +94,18 @@ function onClientResponseFinish({ request, response }) { if (typeof request[kInspectorRequestId] !== 'string') { return; } + + let mimeType; + let charset; + try { + const mimeTypeObj = new MIMEType(response.headers['content-type']); + mimeType = mimeTypeObj.essence || ''; + charset = mimeTypeObj.params.get('charset') || ''; + } catch { + mimeType = ''; + charset = ''; + } + Network.responseReceived({ requestId: request[kInspectorRequestId], timestamp: getMonotonicTime(), @@ -102,6 +115,8 @@ function onClientResponseFinish({ request, response }) { status: response.statusCode, statusText: response.statusMessage ?? '', headers: convertHeaderObject(response.headers)[1], + mimeType, + charset, }, }); diff --git a/lib/internal/inspector/network_undici.js b/lib/internal/inspector/network_undici.js index 636e2b21b45b4a..faa0bc35ec0462 100644 --- a/lib/internal/inspector/network_undici.js +++ b/lib/internal/inspector/network_undici.js @@ -1,6 +1,7 @@ 'use strict'; const { + ArrayPrototypeFindIndex, DateNow, } = primordials; @@ -12,6 +13,7 @@ const { } = require('internal/inspector/network'); const dc = require('diagnostics_channel'); const { Network } = require('inspector'); +const { MIMEType } = require('internal/mime'); // Convert an undici request headers array to a plain object (Map) function requestHeadersArrayToDictionary(headers) { @@ -91,6 +93,21 @@ function onClientResponseHeaders({ request, response }) { if (typeof request[kInspectorRequestId] !== 'string') { return; } + + let mimeType; + let charset; + try { + const contentTypeKeyIndex = + ArrayPrototypeFindIndex(response.headers, (header) => header.toString().toLowerCase() === 'content-type'); + const contentType = contentTypeKeyIndex !== -1 ? response.headers[contentTypeKeyIndex + 1].toString() : ''; + const mimeTypeObj = new MIMEType(contentType); + mimeType = mimeTypeObj.essence || ''; + charset = mimeTypeObj.params.get('charset') || ''; + } catch { + mimeType = ''; + charset = ''; + } + const url = `${request.origin}${request.path}`; Network.responseReceived({ requestId: request[kInspectorRequestId], @@ -102,6 +119,8 @@ function onClientResponseHeaders({ request, response }) { status: response.statusCode, statusText: response.statusText, headers: responseHeadersArrayToDictionary(response.headers), + mimeType, + charset, }, }); } diff --git a/lib/internal/main/embedding.js b/lib/internal/main/embedding.js index 93aa8bb38a06a6..105f4a7b6da777 100644 --- a/lib/internal/main/embedding.js +++ b/lib/internal/main/embedding.js @@ -56,6 +56,7 @@ function embedderRunCjs(content) { function: compiledWrapper, cachedDataRejected, sourceMapURL, + sourceURL, } = compileFunctionForCJSLoader( content, filename, @@ -69,7 +70,7 @@ function embedderRunCjs(content) { content, customModule, false, // isGeneratedSource - undefined, // sourceURL, TODO(joyeecheung): should be extracted by V8 + sourceURL, sourceMapURL, ); } diff --git a/lib/internal/main/watch_mode.js b/lib/internal/main/watch_mode.js index 6ccc90436e6201..dc8323a7c3b377 100644 --- a/lib/internal/main/watch_mode.js +++ b/lib/internal/main/watch_mode.js @@ -43,11 +43,26 @@ const argsWithoutWatchOptions = []; for (let i = 0; i < process.execArgv.length; i++) { const arg = process.execArgv[i]; - if (StringPrototypeStartsWith(arg, '--watch')) { - i++; - const nextArg = process.execArgv[i]; - if (nextArg && nextArg[0] === '-') { - ArrayPrototypePush(argsWithoutWatchOptions, nextArg); + if (StringPrototypeStartsWith(arg, '--watch=')) { + continue; + } + if (arg === '--watch') { + const nextArg = process.execArgv[i + 1]; + if (nextArg && nextArg[0] !== '-') { + // If `--watch` doesn't include `=` and the next + // argument is not a flag then it is interpreted as + // the watch argument, so we need to skip that as well + i++; + } + continue; + } + if (StringPrototypeStartsWith(arg, '--watch-path')) { + const lengthOfWatchPathStr = 12; + if (arg[lengthOfWatchPathStr] !== '=') { + // if --watch-path doesn't include `=` it means + // that the next arg is the target path, so we + // need to skip that as well + i++; } continue; } diff --git a/lib/internal/modules/cjs/loader.js b/lib/internal/modules/cjs/loader.js index ccd2b4ced3134d..d90476addb3f7c 100644 --- a/lib/internal/modules/cjs/loader.js +++ b/lib/internal/modules/cjs/loader.js @@ -1636,9 +1636,9 @@ function wrapSafe(filename, content, cjsModuleInstance, format) { ); // Cache the source map for the module if present. - const { sourceMapURL } = script; + const { sourceMapURL, sourceURL } = script; if (sourceMapURL) { - maybeCacheSourceMap(filename, content, cjsModuleInstance, false, undefined, sourceMapURL); + maybeCacheSourceMap(filename, content, cjsModuleInstance, false, sourceURL, sourceMapURL); } return { @@ -1663,7 +1663,7 @@ function wrapSafe(filename, content, cjsModuleInstance, format) { // Cache the source map for the module if present. if (result.sourceMapURL) { - maybeCacheSourceMap(filename, content, cjsModuleInstance, false, undefined, result.sourceMapURL); + maybeCacheSourceMap(filename, content, cjsModuleInstance, false, result.sourceURL, result.sourceMapURL); } return result; diff --git a/lib/internal/modules/esm/assert.js b/lib/internal/modules/esm/assert.js index 1a96569cce109f..a8e564d6707285 100644 --- a/lib/internal/modules/esm/assert.js +++ b/lib/internal/modules/esm/assert.js @@ -57,7 +57,7 @@ function validateAttributes(url, format, const keys = ObjectKeys(importAttributes); for (let i = 0; i < keys.length; i++) { if (keys[i] !== 'type') { - throw new ERR_IMPORT_ATTRIBUTE_UNSUPPORTED(keys[i], importAttributes[keys[i]]); + throw new ERR_IMPORT_ATTRIBUTE_UNSUPPORTED(keys[i], importAttributes[keys[i]], url); } } const validType = formatTypeMap[format]; @@ -102,7 +102,7 @@ function handleInvalidType(url, type) { // `type` might not have been one of the types we understand. if (!ArrayPrototypeIncludes(supportedTypeAttributes, type)) { - throw new ERR_IMPORT_ATTRIBUTE_UNSUPPORTED('type', type); + throw new ERR_IMPORT_ATTRIBUTE_UNSUPPORTED('type', type, url); } // `type` was the wrong value for this format. diff --git a/lib/internal/modules/esm/formats.js b/lib/internal/modules/esm/formats.js index 608b69caf3fe49..91e3a906c9a34d 100644 --- a/lib/internal/modules/esm/formats.js +++ b/lib/internal/modules/esm/formats.js @@ -7,7 +7,7 @@ const { const { getOptionValue } = require('internal/options'); const { getValidatedPath } = require('internal/fs/utils'); const fsBindings = internalBinding('fs'); -const { fs: fsConstants } = internalBinding('constants'); +const { internal: internalConstants } = internalBinding('constants'); const experimentalWasmModules = getOptionValue('--experimental-wasm-modules'); @@ -55,7 +55,7 @@ function getFormatOfExtensionlessFile(url) { if (!experimentalWasmModules) { return 'module'; } const path = getValidatedPath(url); switch (fsBindings.getFormatOfExtensionlessFile(path)) { - case fsConstants.EXTENSIONLESS_FORMAT_WASM: + case internalConstants.EXTENSIONLESS_FORMAT_WASM: return 'wasm'; default: return 'module'; diff --git a/lib/internal/modules/esm/loader.js b/lib/internal/modules/esm/loader.js index aff686577df3c3..5a817ed0434b8b 100644 --- a/lib/internal/modules/esm/loader.js +++ b/lib/internal/modules/esm/loader.js @@ -378,7 +378,7 @@ class ModuleLoader { throw new ERR_REQUIRE_ASYNC_MODULE(filename, parentFilename); } const status = job.module.getStatus(); - debug('Module status', filename, status); + debug('Module status', job, status); if (status === kEvaluated) { return { wrap: job.module, namespace: job.module.getNamespaceSync(filename, parentFilename) }; } else if (status === kInstantiated) { diff --git a/lib/internal/modules/esm/module_job.js b/lib/internal/modules/esm/module_job.js index 8cfbeeff1ec0a1..d30e6fb5155fc6 100644 --- a/lib/internal/modules/esm/module_job.js +++ b/lib/internal/modules/esm/module_job.js @@ -22,7 +22,14 @@ let debug = require('internal/util/debuglog').debuglog('esm', (fn) => { debug = fn; }); -const { ModuleWrap, kEvaluationPhase, kInstantiated } = internalBinding('module_wrap'); +const { + ModuleWrap, + kErrored, + kEvaluated, + kEvaluationPhase, + kInstantiated, + kUninstantiated, +} = internalBinding('module_wrap'); const { privateSymbols: { entry_point_module_private_symbol, @@ -58,6 +65,37 @@ const isCommonJSGlobalLikeNotDefinedError = (errorMessage) => (globalLike) => errorMessage === `${globalLike} is not defined`, ); + +/** + * + * @param {Error} e + * @param {string} url + * @returns {void} + */ +const explainCommonJSGlobalLikeNotDefinedError = (e, url) => { + if (e?.name === 'ReferenceError' && + isCommonJSGlobalLikeNotDefinedError(e.message)) { + e.message += ' in ES module scope'; + + if (StringPrototypeStartsWith(e.message, 'require ')) { + e.message += ', you can use import instead'; + } + + const packageConfig = + StringPrototypeStartsWith(url, 'file://') && + RegExpPrototypeExec(/\.js(\?[^#]*)?(#.*)?$/, url) !== null && + require('internal/modules/package_json_reader') + .getPackageScopeConfig(url); + if (packageConfig.type === 'module') { + e.message += + '\nThis file is being treated as an ES module because it has a ' + + `'.js' file extension and '${packageConfig.pjsonPath}' contains ` + + '"type": "module". To treat it as a CommonJS script, rename it ' + + 'to use the \'.cjs\' file extension.'; + } + } +}; + class ModuleJobBase { constructor(url, importAttributes, isMain, inspectBrk) { this.importAttributes = importAttributes; @@ -249,17 +287,34 @@ class ModuleJob extends ModuleJobBase { runSync(parent) { assert(this.phase === kEvaluationPhase); assert(this.module instanceof ModuleWrap); - if (this.instantiated !== undefined) { - return { __proto__: null, module: this.module }; + let status = this.module.getStatus(); + + debug('ModuleJob.runSync', this.module); + // FIXME(joyeecheung): this cannot fully handle < kInstantiated. Make the linking + // fully synchronous instead. + if (status === kUninstantiated) { + this.module.async = this.module.instantiateSync(); + status = this.module.getStatus(); } + if (status === kInstantiated || status === kErrored) { + const filename = urlToFilename(this.url); + const parentFilename = urlToFilename(parent?.filename); + this.module.async ??= this.module.isGraphAsync(); - this.module.instantiate(); - this.instantiated = PromiseResolve(); - setHasStartedUserESMExecution(); - const filename = urlToFilename(this.url); - const parentFilename = urlToFilename(parent?.filename); - const namespace = this.module.evaluateSync(filename, parentFilename); - return { __proto__: null, module: this.module, namespace }; + if (this.module.async && !getOptionValue('--experimental-print-required-tla')) { + throw new ERR_REQUIRE_ASYNC_MODULE(filename, parentFilename); + } + if (status === kInstantiated) { + setHasStartedUserESMExecution(); + const namespace = this.module.evaluateSync(filename, parentFilename); + return { __proto__: null, module: this.module, namespace }; + } + throw this.module.getError(); + + } else if (status === kEvaluated) { + return { __proto__: null, module: this.module, namespace: this.module.getNamespaceSync() }; + } + assert.fail(`Unexpected module status ${status}.`); } async run(isEntryPoint = false) { @@ -273,27 +328,7 @@ class ModuleJob extends ModuleJobBase { try { await this.module.evaluate(timeout, breakOnSigint); } catch (e) { - if (e?.name === 'ReferenceError' && - isCommonJSGlobalLikeNotDefinedError(e.message)) { - e.message += ' in ES module scope'; - - if (StringPrototypeStartsWith(e.message, 'require ')) { - e.message += ', you can use import instead'; - } - - const packageConfig = - StringPrototypeStartsWith(this.module.url, 'file://') && - RegExpPrototypeExec(/\.js(\?[^#]*)?(#.*)?$/, this.module.url) !== null && - require('internal/modules/package_json_reader') - .getPackageScopeConfig(this.module.url); - if (packageConfig.type === 'module') { - e.message += - '\nThis file is being treated as an ES module because it has a ' + - `'.js' file extension and '${packageConfig.pjsonPath}' contains ` + - '"type": "module". To treat it as a CommonJS script, rename it ' + - 'to use the \'.cjs\' file extension.'; - } - } + explainCommonJSGlobalLikeNotDefinedError(e, this.module.url); throw e; } return { __proto__: null, module: this.module }; @@ -397,8 +432,13 @@ class ModuleJobSync extends ModuleJobBase { throw new ERR_REQUIRE_ASYNC_MODULE(filename, parentFilename); } setHasStartedUserESMExecution(); - const namespace = this.module.evaluateSync(filename, parentFilename); - return { __proto__: null, module: this.module, namespace }; + try { + const namespace = this.module.evaluateSync(filename, parentFilename); + return { __proto__: null, module: this.module, namespace }; + } catch (e) { + explainCommonJSGlobalLikeNotDefinedError(e, this.module.url); + throw e; + } } } diff --git a/lib/internal/modules/esm/translators.js b/lib/internal/modules/esm/translators.js index 7dcd7afe8ce3c2..0695b47a8a8f78 100644 --- a/lib/internal/modules/esm/translators.js +++ b/lib/internal/modules/esm/translators.js @@ -120,10 +120,10 @@ translators.set('module', function moduleStrategy(url, source, isMain) { function loadCJSModule(module, source, url, filename, isMain) { const compileResult = compileFunctionForCJSLoader(source, filename, false /* is_sea_main */, false); - const { function: compiledWrapper, sourceMapURL } = compileResult; + const { function: compiledWrapper, sourceMapURL, sourceURL } = compileResult; // Cache the source map for the cjs module if present. if (sourceMapURL) { - maybeCacheSourceMap(url, source, module, false, undefined, sourceMapURL); + maybeCacheSourceMap(url, source, module, false, sourceURL, sourceMapURL); } const cascadedLoader = require('internal/modules/esm/loader').getOrInitializeCascadedLoader(); diff --git a/lib/internal/modules/esm/utils.js b/lib/internal/modules/esm/utils.js index fd17ce8695c55f..9d6f850f667c51 100644 --- a/lib/internal/modules/esm/utils.js +++ b/lib/internal/modules/esm/utils.js @@ -348,7 +348,7 @@ function compileSourceTextModule(url, source, cascadedLoader) { } // Cache the source map for the module if present. if (wrap.sourceMapURL) { - maybeCacheSourceMap(url, source, wrap, false, undefined, wrap.sourceMapURL); + maybeCacheSourceMap(url, source, wrap, false, wrap.sourceURL, wrap.sourceMapURL); } return wrap; } diff --git a/lib/internal/readline/interface.js b/lib/internal/readline/interface.js index 91dfcb641eb6aa..a076799a890106 100644 --- a/lib/internal/readline/interface.js +++ b/lib/internal/readline/interface.js @@ -47,7 +47,11 @@ const { validateString, validateUint32, } = require('internal/validators'); -const { SymbolDispose, kEmptyObject } = require('internal/util'); +const { + assignFunctionName, + kEmptyObject, + SymbolDispose, +} = require('internal/util'); const { inspect, getStringWidth, @@ -1370,7 +1374,9 @@ class Interface extends InterfaceConstructor { return this[kLineObjectStream]; } } -Interface.prototype[SymbolDispose] = Interface.prototype.close; +Interface.prototype[SymbolDispose] = assignFunctionName(SymbolDispose, function() { + this.close(); +}); module.exports = { Interface, diff --git a/lib/internal/source_map/source_map_cache.js b/lib/internal/source_map/source_map_cache.js index 639051ec10fe61..603685290ad85f 100644 --- a/lib/internal/source_map/source_map_cache.js +++ b/lib/internal/source_map/source_map_cache.js @@ -10,7 +10,7 @@ const { StringPrototypeSplit, } = primordials; -// See https://sourcemaps.info/spec.html for SourceMap V3 specification. +// See https://tc39.es/ecma426/ for SourceMap V3 specification. const { Buffer } = require('buffer'); let debug = require('internal/util/debuglog').debuglog('source_map', (fn) => { debug = fn; @@ -139,7 +139,9 @@ function extractSourceMapURLMagicComment(content) { } /** - * Caches the source map if it is present in the content, with the given filename, moduleInstance, and sourceURL. + * Caches the source map, with the given filename, moduleInstance, sourceURL and sourceMapURL. + * This function does not automatically extract the source map from the content. The caller should either + * extract the source map from the content via V8 API or use {@link extractSourceURLMagicComment} explicitly. * @param {string} filename - the actual filename * @param {string} content - the actual source content * @param {import('internal/modules/cjs/loader').Module | ModuleWrap} moduleInstance - a module instance that @@ -162,20 +164,13 @@ function maybeCacheSourceMap(filename, content, moduleInstance, isGeneratedSourc return; } - if (sourceMapURL === undefined) { - sourceMapURL = extractSourceMapURLMagicComment(content); - } - // Bail out when there is no source map url. if (typeof sourceMapURL !== 'string') { return; } - // FIXME: callers should obtain sourceURL from v8 and pass it - // rather than leaving it undefined and extract by regex. - if (sourceURL === undefined) { - sourceURL = extractSourceURLMagicComment(content); - } + // Normalize the sourceURL to a file URL if it is a path. + sourceURL = normalizeReferrerURL(sourceURL); const data = dataFromUrl(filename, sourceMapURL); // `data` could be null if the source map is invalid. @@ -192,9 +187,6 @@ function maybeCacheSourceMap(filename, content, moduleInstance, isGeneratedSourc if (isGeneratedSource) { generatedSourceMapCache.set(filename, entry); - if (sourceURL) { - generatedSourceMapCache.set(sourceURL, entry); - } return; } // If it is not a generated source, we assume we are in a "cjs/esm" @@ -215,8 +207,14 @@ function maybeCacheGeneratedSourceMap(content) { if (sourceURL === null) { return; } + const sourceMapURL = extractSourceMapURLMagicComment(content); + if (sourceMapURL === null) { + return; + } + try { - maybeCacheSourceMap(sourceURL, content, null, true, sourceURL); + // Use the sourceURL as the filename, and do not create a duplicate entry. + maybeCacheSourceMap(sourceURL, content, null, true, undefined /** no duplicated sourceURL */, sourceMapURL); } catch (err) { // This can happen if the filename is not a valid URL. // If we fail to cache the source map, we should not fail the whole process. diff --git a/lib/internal/streams/readable.js b/lib/internal/streams/readable.js index 3079474b026f52..d02f595fa328b8 100644 --- a/lib/internal/streams/readable.js +++ b/lib/internal/streams/readable.js @@ -371,13 +371,13 @@ Readable.prototype[EE.captureRejectionSymbol] = function(err) { this.destroy(err); }; -Readable.prototype[SymbolAsyncDispose] = function() { +Readable.prototype[SymbolAsyncDispose] = async function() { let error; if (!this.destroyed) { error = this.readableEnded ? null : new AbortError(); this.destroy(error); } - return new Promise((resolve, reject) => eos(this, (err) => (err && err !== error ? reject(err) : resolve(null)))); + await new Promise((resolve, reject) => eos(this, (err) => (err && err !== error ? reject(err) : resolve(null)))); }; // Manually shove something into the read() buffer. diff --git a/lib/internal/streams/writable.js b/lib/internal/streams/writable.js index b74b60882017f6..a3a1a965b00a87 100644 --- a/lib/internal/streams/writable.js +++ b/lib/internal/streams/writable.js @@ -1151,13 +1151,13 @@ Writable.toWeb = function(streamWritable) { return lazyWebStreams().newWritableStreamFromStreamWritable(streamWritable); }; -Writable.prototype[SymbolAsyncDispose] = function() { +Writable.prototype[SymbolAsyncDispose] = async function() { let error; if (!this.destroyed) { error = this.writableFinished ? null : new AbortError(); this.destroy(error); } - return new Promise((resolve, reject) => + await new Promise((resolve, reject) => eos(this, (err) => (err && err.name !== 'AbortError' ? reject(err) : resolve(null))), ); }; diff --git a/lib/internal/test_runner/coverage.js b/lib/internal/test_runner/coverage.js index a88f6744f770d2..24422bd12576c2 100644 --- a/lib/internal/test_runner/coverage.js +++ b/lib/internal/test_runner/coverage.js @@ -409,6 +409,10 @@ class TestCoverage { } const mappedStartOffset = this.entryToOffset(startEntry, mappedLines); const mappedEndOffset = this.entryToOffset(endEntry, mappedLines) + 1; + if (mappedStartOffset < 0 || mappedEndOffset < 1) { + // The range is not mappable. Skip it. + continue; + } for (let l = startEntry.originalLine; l <= endEntry.originalLine; l++) { mappedLines[l].count = count; } @@ -433,7 +437,12 @@ class TestCoverage { entryToOffset(entry, lines) { const line = MathMax(entry.originalLine, 0); - return MathMin(lines[line].startOffset + entry.originalColumn, lines[line].endOffset); + const mappedLine = lines[line]; + if (!mappedLine) { + // Return -1 if the line is not mappable. + return -1; + } + return MathMin(mappedLine.startOffset + entry.originalColumn, mappedLine.endOffset); } mergeCoverage(merged, coverage) { diff --git a/lib/internal/test_runner/mock/loader.js b/lib/internal/test_runner/mock/loader.js index bfdfe93741c2cc..6739bded60ff44 100644 --- a/lib/internal/test_runner/mock/loader.js +++ b/lib/internal/test_runner/mock/loader.js @@ -118,10 +118,17 @@ async function load(url, context, nextLoad) { // Treat builtins as commonjs because customization hooks do not allow a // core module to be replaced. // Also collapse 'commonjs-sync' and 'require-commonjs' to 'commonjs'. - const format = ( - original.format === 'builtin' || - original.format === 'commonjs-sync' || - original.format === 'require-commonjs') ? 'commonjs' : original.format; + let format = original.format; + switch (original.format) { + case 'builtin': // Deliberate fallthrough + case 'commonjs-sync': // Deliberate fallthrough + case 'require-commonjs': + format = 'commonjs'; + break; + case 'json': + format = 'module'; + break; + } const result = { __proto__: null, diff --git a/lib/internal/test_runner/mock/mock.js b/lib/internal/test_runner/mock/mock.js index 99fe1baebb771b..178da37efc16c8 100644 --- a/lib/internal/test_runner/mock/mock.js +++ b/lib/internal/test_runner/mock/mock.js @@ -70,7 +70,14 @@ const kMockUnknownMessage = 3; const kWaitTimeout = 5_000; const kBadExportsMessage = 'Cannot create mock because named exports ' + 'cannot be applied to the provided default export.'; -const kSupportedFormats = ['builtin', 'commonjs', 'module', 'module-typescript', 'commonjs-typescript']; +const kSupportedFormats = [ + 'builtin', + 'commonjs-typescript', + 'commonjs', + 'json', + 'module-typescript', + 'module', +]; let sharedModuleState; class MockFunctionContext { diff --git a/lib/internal/test_runner/reporter/spec.js b/lib/internal/test_runner/reporter/spec.js index e03c8df9e82489..9031025e57d930 100644 --- a/lib/internal/test_runner/reporter/spec.js +++ b/lib/internal/test_runner/reporter/spec.js @@ -94,8 +94,10 @@ class SpecReporter extends Transform { case 'test:stderr': case 'test:stdout': return data.message; - case 'test:diagnostic': - return `${reporterColorMap[type]}${indent(data.nesting)}${reporterUnicodeSymbolMap[type]}${data.message}${colors.white}\n`; + case 'test:diagnostic':{ + const diagnosticColor = reporterColorMap[data.level] || reporterColorMap['test:diagnostic']; + return `${diagnosticColor}${indent(data.nesting)}${reporterUnicodeSymbolMap[type]}${data.message}${colors.white}\n`; + } case 'test:coverage': return getCoverageReport(indent(data.nesting), data.summary, reporterUnicodeSymbolMap['test:coverage'], colors.blue, true); diff --git a/lib/internal/test_runner/reporter/utils.js b/lib/internal/test_runner/reporter/utils.js index 256619039e8e90..eb1a008aaf006a 100644 --- a/lib/internal/test_runner/reporter/utils.js +++ b/lib/internal/test_runner/reporter/utils.js @@ -37,6 +37,15 @@ const reporterColorMap = { get 'test:diagnostic'() { return colors.blue; }, + get 'info'() { + return colors.blue; + }, + get 'warn'() { + return colors.yellow; + }, + get 'error'() { + return colors.red; + }, }; function indent(nesting) { diff --git a/lib/internal/test_runner/test.js b/lib/internal/test_runner/test.js index 49598e6595825d..2bb70493f82182 100644 --- a/lib/internal/test_runner/test.js +++ b/lib/internal/test_runner/test.js @@ -1217,7 +1217,7 @@ class Test extends AsyncResource { if (actual < threshold) { harness.success = false; process.exitCode = kGenericUserError; - reporter.diagnostic(nesting, loc, `Error: ${NumberPrototypeToFixed(actual, 2)}% ${name} coverage does not meet threshold of ${threshold}%.`); + reporter.diagnostic(nesting, loc, `Error: ${NumberPrototypeToFixed(actual, 2)}% ${name} coverage does not meet threshold of ${threshold}%.`, 'error'); } } diff --git a/lib/internal/test_runner/tests_stream.js b/lib/internal/test_runner/tests_stream.js index 2fda1e68069c19..318d7f49998c0e 100644 --- a/lib/internal/test_runner/tests_stream.js +++ b/lib/internal/test_runner/tests_stream.js @@ -116,11 +116,12 @@ class TestsStream extends Readable { }); } - diagnostic(nesting, loc, message) { + diagnostic(nesting, loc, message, level = 'info') { this[kEmitMessage]('test:diagnostic', { __proto__: null, nesting, message, + level, ...loc, }); } diff --git a/lib/internal/tty.js b/lib/internal/tty.js index 486c2d06e7e9b8..0e3d901804f99e 100644 --- a/lib/internal/tty.js +++ b/lib/internal/tty.js @@ -24,7 +24,10 @@ const { ArrayPrototypeSome, + ObjectEntries, + ObjectPrototypeHasOwnProperty: hasOwn, RegExpPrototypeExec, + SafeMap, StringPrototypeSplit, StringPrototypeToLowerCase, } = primordials; @@ -64,17 +67,31 @@ const TERM_ENVS = { 'rxvt-unicode-24bit': COLORS_16m, // https://bugs.launchpad.net/terminator/+bug/1030562 'terminator': COLORS_16m, + 'xterm-kitty': COLORS_16m, }; +const CI_ENVS_MAP = new SafeMap(ObjectEntries({ + APPVEYOR: COLORS_256, + BUILDKITE: COLORS_256, + CIRCLECI: COLORS_16m, + DRONE: COLORS_256, + GITEA_ACTIONS: COLORS_16m, + GITHUB_ACTIONS: COLORS_16m, + GITLAB_CI: COLORS_256, + TRAVIS: COLORS_256, +})); + const TERM_ENVS_REG_EXP = [ /ansi/, /color/, /linux/, + /direct/, /^con[0-9]*x[0-9]/, /^rxvt/, /^screen/, /^xterm/, /^vt100/, + /^vt220/, ]; let warned = false; @@ -155,19 +172,21 @@ function getColorDepth(env = process.env) { } if (env.TMUX) { - return COLORS_256; + return COLORS_16m; + } + + // Azure DevOps + if (hasOwn(env, 'TF_BUILD') && hasOwn(env, 'AGENT_NAME')) { + return COLORS_16; } - if (env.CI) { - if ([ - 'APPVEYOR', - 'BUILDKITE', - 'CIRCLECI', - 'DRONE', - 'GITHUB_ACTIONS', - 'GITLAB_CI', - 'TRAVIS', - ].some((sign) => sign in env) || env.CI_NAME === 'codeship') { + if (hasOwn(env, 'CI')) { + for (const { 0: envName, 1: colors } of CI_ENVS_MAP) { + if (hasOwn(env, envName)) { + return colors; + } + } + if (env.CI_NAME === 'codeship') { return COLORS_256; } return COLORS_2; @@ -198,6 +217,10 @@ function getColorDepth(env = process.env) { } if (env.TERM) { + if (RegExpPrototypeExec(/truecolor/, env.TERM) !== null) { + return COLORS_16m; + } + if (RegExpPrototypeExec(/^xterm-256/, env.TERM) !== null) { return COLORS_256; } diff --git a/lib/internal/util.js b/lib/internal/util.js index 254791eb489c66..a27815cc029cc5 100644 --- a/lib/internal/util.js +++ b/lib/internal/util.js @@ -41,6 +41,7 @@ const { StringPrototypeToUpperCase, Symbol, SymbolFor, + SymbolPrototypeGetDescription, SymbolReplace, SymbolSplit, } = primordials; @@ -67,6 +68,7 @@ const { } = internalBinding('util'); const { isNativeError, isPromise } = internalBinding('types'); const { getOptionValue } = require('internal/options'); +const assert = require('internal/assert'); const { encodings } = internalBinding('string_decoder'); const noCrypto = !process.versions.openssl; @@ -897,10 +899,37 @@ const encodingsMap = { __proto__: null }; for (let i = 0; i < encodings.length; ++i) encodingsMap[encodings[i]] = i; +/** + * Reassigns the .name property of a function. + * Should be used when function can't be initially defined with desired name + * or when desired name should include `#`, `[`, `]`, etc. + * @param {string | symbol} name + * @param {Function} fn + * @param {object} [descriptor] + * @returns {Function} the same function, renamed + */ +function assignFunctionName(name, fn, descriptor = kEmptyObject) { + if (typeof name !== 'string') { + const symbolDescription = SymbolPrototypeGetDescription(name); + assert(symbolDescription !== undefined, 'Attempted to name function after descriptionless Symbol'); + name = `[${symbolDescription}]`; + } + return ObjectDefineProperty(fn, 'name', { + __proto__: null, + writable: false, + enumerable: false, + configurable: true, + ...ObjectGetOwnPropertyDescriptor(fn, 'name'), + ...descriptor, + value: name, + }); +} + module.exports = { getLazy, assertCrypto, assertTypeScript, + assignFunctionName, cachedResult, convertToValidSignal, createClassWrapper, diff --git a/lib/internal/webstreams/compression.js b/lib/internal/webstreams/compression.js index 2299b9c49e05bd..b33b7134096c8b 100644 --- a/lib/internal/webstreams/compression.js +++ b/lib/internal/webstreams/compression.js @@ -99,16 +99,28 @@ class DecompressionStream { }); switch (format) { case 'deflate': - this.#handle = lazyZlib().createInflate(); + this.#handle = lazyZlib().createInflate({ + rejectGarbageAfterEnd: true, + }); break; case 'deflate-raw': this.#handle = lazyZlib().createInflateRaw(); break; case 'gzip': - this.#handle = lazyZlib().createGunzip(); + this.#handle = lazyZlib().createGunzip({ + rejectGarbageAfterEnd: true, + }); break; } this.#transform = newReadableWritablePairFromDuplex(this.#handle); + + this.#handle.on('error', (err) => { + if (this.#transform?.writable && + !this.#transform.writable.locked && + typeof this.#transform.writable.abort === 'function') { + this.#transform.writable.abort(err); + } + }); } /** diff --git a/lib/internal/worker/io.js b/lib/internal/worker/io.js index 29c7914982b67a..786ee36c1927fa 100644 --- a/lib/internal/worker/io.js +++ b/lib/internal/worker/io.js @@ -18,6 +18,7 @@ const { } = primordials; const { + assignFunctionName, kEnumerableProperty, setOwnProperty, } = require('internal/util'); @@ -121,7 +122,7 @@ ObjectSetPrototypeOf(MessagePort.prototype, NodeEventTarget.prototype); // changing the prototype of MessagePort.prototype implicitly removed them. MessagePort.prototype.ref = MessagePortPrototype.ref; MessagePort.prototype.unref = MessagePortPrototype.unref; -MessagePort.prototype.hasRef = function() { +MessagePort.prototype.hasRef = function hasRef() { return !!FunctionPrototypeCall(MessagePortPrototype.hasRef, this); }; @@ -131,14 +132,14 @@ ObjectDefineProperty( kCreateEvent, { __proto__: null, - value: function(data, type) { + value: assignFunctionName(kCreateEvent, function(data, type) { if (type !== 'message' && type !== 'messageerror') { return ReflectApply(originalCreateEvent, this, arguments); } const ports = this[kCurrentlyReceivingPorts]; this[kCurrentlyReceivingPorts] = undefined; return lazyMessageEvent(type, { data, ports }); - }, + }), configurable: false, writable: false, enumerable: false, @@ -179,7 +180,7 @@ ObjectDefineProperty(MessagePort.prototype, handleOnCloseSymbol, { value: onclose, }); -MessagePort.prototype.close = function(cb) { +MessagePort.prototype.close = function close(cb) { if (typeof cb === 'function') this.once('close', cb); FunctionPrototypeCall(MessagePortPrototype.close, this); diff --git a/lib/net.js b/lib/net.js index f1cda502e5fb75..8019c5a4be8aa7 100644 --- a/lib/net.js +++ b/lib/net.js @@ -238,11 +238,6 @@ function connect(...args) { debug('createConnection', normalized); const socket = new Socket(options); - if (netClientSocketChannel.hasSubscribers) { - netClientSocketChannel.publish({ - socket, - }); - } if (options.timeout) { socket.setTimeout(options.timeout); } @@ -1238,6 +1233,12 @@ Socket.prototype.connect = function(...args) { const options = normalized[0]; const cb = normalized[1]; + if (netClientSocketChannel.hasSubscribers) { + netClientSocketChannel.publish({ + socket: this, + }); + } + if (cb !== null) { this.once('connect', cb); } @@ -2394,7 +2395,7 @@ Server.prototype[SymbolAsyncDispose] = async function() { if (!this._handle) { return; } - return FunctionPrototypeCall(promisify(this.close), this); + await FunctionPrototypeCall(promisify(this.close), this); }; Server.prototype._emitCloseIfDrained = function() { diff --git a/lib/path.js b/lib/path.js index 5632fa1dea70c1..e35147f4b2e159 100644 --- a/lib/path.js +++ b/lib/path.js @@ -54,7 +54,6 @@ const { const { getLazy, - emitExperimentalWarning, isWindows, isMacOS, } = require('internal/util'); @@ -97,7 +96,7 @@ function normalizeString(path, allowAboveRoot, separator, isPathSeparator) { StringPrototypeCharCodeAt(res, res.length - 1) !== CHAR_DOT || StringPrototypeCharCodeAt(res, res.length - 2) !== CHAR_DOT) { if (res.length > 2) { - const lastSlashIndex = StringPrototypeLastIndexOf(res, separator); + const lastSlashIndex = res.length - lastSegmentLength - 1; if (lastSlashIndex === -1) { res = ''; lastSegmentLength = 0; @@ -166,7 +165,6 @@ function _format(sep, pathObject) { } function glob(path, pattern, windows) { - emitExperimentalWarning('glob'); validateString(path, 'path'); validateString(pattern, 'pattern'); return lazyMinimatch().minimatch(path, pattern, { @@ -180,6 +178,7 @@ function glob(path, pattern, windows) { nocaseMagicOnly: true, }); } +const forwardSlashRegExp = /\//g; const win32 = { /** @@ -204,6 +203,14 @@ const win32 = { } } else if (resolvedDevice.length === 0) { path = process.cwd(); + // Fast path for current directory + if (args.length === 0 || ((args.length === 1 && (args[0] === '' || args[0] === '.')) && + isPathSeparator(StringPrototypeCharCodeAt(path, 0)))) { + if (!isWindows) { + path = StringPrototypeReplace(path, forwardSlashRegExp, '\\'); + } + return path; + } } else { // Windows has the concept of drive-specific current working // directories. If we've resolved a drive letter but not yet an @@ -1178,6 +1185,12 @@ const posix = { * @returns {string} */ resolve(...args) { + if (args.length === 0 || (args.length === 1 && (args[0] === '' || args[0] === '.'))) { + const cwd = posixCwd(); + if (StringPrototypeCharCodeAt(cwd, 0) === CHAR_FORWARD_SLASH) { + return cwd; + } + } let resolvedPath = ''; let resolvedAbsolute = false; diff --git a/lib/url.js b/lib/url.js index 8acec11816f88e..b41e7664e93b8d 100644 --- a/lib/url.js +++ b/lib/url.js @@ -27,6 +27,9 @@ const { ObjectAssign, ObjectKeys, StringPrototypeCharCodeAt, + StringPrototypeIndexOf, + StringPrototypeReplaceAll, + StringPrototypeSlice, decodeURIComponent, } = primordials; @@ -637,6 +640,10 @@ Url.prototype.format = function format() { } let protocol = this.protocol || ''; + if (protocol && StringPrototypeCharCodeAt(protocol, protocol.length - 1) !== 58 /* : */) { + protocol += ':'; + } + let pathname = this.pathname || ''; let hash = this.hash || ''; let host = ''; @@ -646,7 +653,7 @@ Url.prototype.format = function format() { host = auth + this.host; } else if (this.hostname) { host = auth + ( - this.hostname.includes(':') && !isIpv6Hostname(this.hostname) ? + StringPrototypeIndexOf(this.hostname, ':') !== -1 && !isIpv6Hostname(this.hostname) ? '[' + this.hostname + ']' : this.hostname ); @@ -658,59 +665,55 @@ Url.prototype.format = function format() { if (this.query !== null && typeof this.query === 'object') { query = querystring.stringify(this.query); } - let search = this.search || (query && ('?' + query)) || ''; - if (protocol && protocol.charCodeAt(protocol.length - 1) !== 58/* : */) - protocol += ':'; - - let newPathname = ''; - let lastPos = 0; - for (let i = 0; i < pathname.length; ++i) { - switch (pathname.charCodeAt(i)) { - case CHAR_HASH: - if (i - lastPos > 0) - newPathname += pathname.slice(lastPos, i); - newPathname += '%23'; - lastPos = i + 1; - break; - case CHAR_QUESTION_MARK: - if (i - lastPos > 0) - newPathname += pathname.slice(lastPos, i); - newPathname += '%3F'; + if (StringPrototypeIndexOf(pathname, '#') !== -1 || StringPrototypeIndexOf(pathname, '?') !== -1) { + let newPathname = ''; + let lastPos = 0; + const len = pathname.length; + for (let i = 0; i < len; i++) { + const code = StringPrototypeCharCodeAt(pathname, i); + if (code === CHAR_HASH || code === CHAR_QUESTION_MARK) { + if (i > lastPos) { + newPathname += StringPrototypeSlice(pathname, lastPos, i); + } + newPathname += (code === CHAR_HASH ? '%23' : '%3F'); lastPos = i + 1; - break; + } } - } - if (lastPos > 0) { - if (lastPos !== pathname.length) - pathname = newPathname + pathname.slice(lastPos); - else - pathname = newPathname; + if (lastPos < len) { + newPathname += StringPrototypeSlice(pathname, lastPos); + } + pathname = newPathname; } // Only the slashedProtocols get the //. Not mailto:, xmpp:, etc. // unless they had them to begin with. if (this.slashes || slashedProtocol.has(protocol)) { if (this.slashes || host) { - if (pathname && pathname.charCodeAt(0) !== CHAR_FORWARD_SLASH) + if (pathname && StringPrototypeCharCodeAt(pathname, 0) !== CHAR_FORWARD_SLASH) pathname = '/' + pathname; host = '//' + host; } else if (protocol.length >= 4 && - protocol.charCodeAt(0) === 102/* f */ && - protocol.charCodeAt(1) === 105/* i */ && - protocol.charCodeAt(2) === 108/* l */ && - protocol.charCodeAt(3) === 101/* e */) { + StringPrototypeCharCodeAt(protocol, 0) === 102/* f */ && + StringPrototypeCharCodeAt(protocol, 1) === 105/* i */ && + StringPrototypeCharCodeAt(protocol, 2) === 108/* l */ && + StringPrototypeCharCodeAt(protocol, 3) === 101/* e */) { host = '//'; } } - search = search.replaceAll('#', '%23'); + // Escape '#' in search. + if (StringPrototypeIndexOf(search, '#') !== -1) { + search = StringPrototypeReplaceAll(search, '#', '%23'); + } - if (hash && hash.charCodeAt(0) !== CHAR_HASH) + if (hash && StringPrototypeCharCodeAt(hash, 0) !== CHAR_HASH) { hash = '#' + hash; - if (search && search.charCodeAt(0) !== CHAR_QUESTION_MARK) + } + if (search && StringPrototypeCharCodeAt(search, 0) !== CHAR_QUESTION_MARK) { search = '?' + search; + } return protocol + host + pathname + search + hash; }; diff --git a/lib/util.js b/lib/util.js index a8a2bea01a0f4d..dba1bfba367652 100644 --- a/lib/util.js +++ b/lib/util.js @@ -217,10 +217,11 @@ function pad(n) { } /** - * @param {string} code + * @param {string} [code] * @returns {string} */ function escapeStyleCode(code) { + if (code === undefined) return ''; return `\u001b[${code}m`; } @@ -256,6 +257,7 @@ function styleText(format, text, { validateStream = true, stream = process.stdou let left = ''; let right = ''; for (const key of formatArray) { + if (key === 'none') continue; const formatCodes = inspect.colors[key]; // If the format is not a valid style, throw an error if (formatCodes == null) { diff --git a/lib/zlib.js b/lib/zlib.js index a9f11087218794..590c6edd118903 100644 --- a/lib/zlib.js +++ b/lib/zlib.js @@ -42,6 +42,7 @@ const { ERR_BUFFER_TOO_LARGE, ERR_INVALID_ARG_TYPE, ERR_OUT_OF_RANGE, + ERR_TRAILING_JUNK_AFTER_STREAM_END, ERR_ZSTD_INVALID_PARAM, }, genericNodeError, @@ -266,6 +267,8 @@ function ZlibBase(opts, mode, handle, { flush, finishFlush, fullFlush }) { this._defaultFullFlushFlag = fullFlush; this._info = opts?.info; this._maxOutputLength = maxOutputLength; + + this._rejectGarbageAfterEnd = opts?.rejectGarbageAfterEnd === true; } ObjectSetPrototypeOf(ZlibBase.prototype, Transform.prototype); ObjectSetPrototypeOf(ZlibBase, Transform); @@ -322,7 +325,7 @@ ZlibBase.prototype._final = function(callback) { // This is currently only used to figure out which flush flag to use for the // last chunk. // Roughly, the following holds: -// Z_NO_FLUSH (< Z_TREES) < Z_BLOCK < Z_PARTIAL_FLUSH < +// Z_NO_FLUSH < Z_BLOCK < Z_PARTIAL_FLUSH < // Z_SYNC_FLUSH < Z_FULL_FLUSH < Z_FINISH const flushiness = []; const kFlushFlagList = [Z_NO_FLUSH, Z_BLOCK, Z_PARTIAL_FLUSH, @@ -588,6 +591,14 @@ function processCallback() { // stream has ended early. // This applies to streams where we don't check data past the end of // what was consumed; that is, everything except Gunzip/Unzip. + + if (self._rejectGarbageAfterEnd) { + const err = new ERR_TRAILING_JUNK_AFTER_STREAM_END(); + self.destroy(err); + this.cb(err); + return; + } + self.push(null); } @@ -680,6 +691,7 @@ function Zlib(opts, mode) { this._level = level; this._strategy = strategy; + this._mode = mode; } ObjectSetPrototypeOf(Zlib.prototype, ZlibBase.prototype); ObjectSetPrototypeOf(Zlib, ZlibBase); diff --git a/node.gni b/node.gni index a2123cc6c6d21c..35ccd0487f20ce 100644 --- a/node.gni +++ b/node.gni @@ -14,7 +14,7 @@ declare_args() { node_openssl_path = "$node_path/deps/openssl" # The location of simdutf - use the one from node's deps by default. - node_simdutf_path = "$node_path/deps/simdutf" + node_simdutf_path = "//third_party/simdutf" # The NODE_MODULE_VERSION defined in node_version.h. node_module_version = exec_script("$node_path/tools/getmoduleversion.py", [], "value") diff --git a/node.gyp b/node.gyp index ad010a8d99cf08..0434887c363a58 100644 --- a/node.gyp +++ b/node.gyp @@ -25,6 +25,7 @@ 'node_shared_uvwasi%': 'false', 'node_shared_nghttp2%': 'false', 'node_use_openssl%': 'true', + 'node_use_sqlite%': 'true', 'node_shared_openssl%': 'false', 'node_v8_options%': '', 'node_enable_v8_vtunejit%': 'false', @@ -140,7 +141,6 @@ 'src/node_shadow_realm.cc', 'src/node_snapshotable.cc', 'src/node_sockaddr.cc', - 'src/node_sqlite.cc', 'src/node_stat_watcher.cc', 'src/node_symbols.cc', 'src/node_task_queue.cc', @@ -153,7 +153,6 @@ 'src/node_wasi.cc', 'src/node_wasm_web_api.cc', 'src/node_watchdog.cc', - 'src/node_webstorage.cc', 'src/node_worker.cc', 'src/node_zlib.cc', 'src/path.cc', @@ -273,7 +272,6 @@ 'src/node_snapshot_builder.h', 'src/node_sockaddr.h', 'src/node_sockaddr-inl.h', - 'src/node_sqlite.h', 'src/node_stat_watcher.h', 'src/node_union_bytes.h', 'src/node_url.h', @@ -282,7 +280,6 @@ 'src/node_v8_platform-inl.h', 'src/node_wasi.h', 'src/node_watchdog.h', - 'src/node_webstorage.h', 'src/node_worker.h', 'src/path.h', 'src/permission/child_process_permission.h', @@ -415,6 +412,12 @@ 'test/cctest/test_inspector_socket.cc', 'test/cctest/test_inspector_socket_server.cc', ], + 'node_sqlite_sources': [ + 'src/node_sqlite.cc', + 'src/node_webstorage.cc', + 'src/node_sqlite.h', + 'src/node_webstorage.h', + ], 'node_mksnapshot_exec': '<(PRODUCT_DIR)/<(EXECUTABLE_PREFIX)node_mksnapshot<(EXECUTABLE_SUFFIX)', 'node_js2c_exec': '<(PRODUCT_DIR)/<(EXECUTABLE_PREFIX)node_js2c<(EXECUTABLE_SUFFIX)', 'conditions': [ @@ -510,7 +513,7 @@ 'target_name': 'node_text_start', 'type': 'none', 'conditions': [ - [ 'OS in "linux freebsd solaris" and ' + [ 'OS in "linux freebsd solaris openharmony" and ' 'target_arch=="x64"', { 'type': 'static_library', 'sources': [ @@ -628,7 +631,7 @@ 'OTHER_LDFLAGS': [ '-Wl,-rpath,@loader_path', '-Wl,-rpath,@loader_path/../lib'], }, 'conditions': [ - ['OS=="linux"', { + ['OS=="linux" or OS=="openharmony"', { 'ldflags': [ '-Wl,-rpath,\\$$ORIGIN/../lib' ], @@ -733,7 +736,7 @@ 'src/node_snapshot_stub.cc' ], }], - [ 'OS in "linux freebsd" and ' + [ 'OS in "linux freebsd openharmony" and ' 'target_arch=="x64"', { 'dependencies': [ 'node_text_start' ], 'ldflags+': [ @@ -899,6 +902,12 @@ 'src/node_snapshot_stub.cc', ] }], + [ 'node_use_sqlite=="true"', { + 'sources': [ + '<@(node_sqlite_sources)', + ], + 'defines': [ 'HAVE_SQLITE=1' ], + }], [ 'node_shared=="true" and node_module_version!="" and OS!="win"', { 'product_extension': '<(shlib_suffix)', 'xcode_settings': { @@ -943,7 +952,13 @@ 'deps/ncrypto/ncrypto.gyp:ncrypto', ], }], - [ 'OS in "linux freebsd mac solaris" and ' + [ 'node_use_sqlite=="true"', { + 'sources': [ + '<@(node_sqlite_sources)', + ], + 'defines': [ 'HAVE_SQLITE=1' ], + }], + [ 'OS in "linux freebsd mac solaris openharmony" and ' 'target_arch=="x64" and ' 'node_target_type=="executable"', { 'defines': [ 'NODE_ENABLE_LARGE_CODE_PAGES=1' ], @@ -1052,11 +1067,11 @@ 'test/fuzzers/fuzz_env.cc', ], 'conditions': [ - ['OS=="linux"', { + ['OS=="linux" or OS=="openharmony"', { 'ldflags': [ '-fsanitize=fuzzer' ] }], # Ensure that ossfuzz flag has been set and that we are on Linux - [ 'OS!="linux" or ossfuzz!="true"', { + [ 'OS not in "linux openharmony" or ossfuzz!="true"', { 'type': 'none', }], # Avoid excessive LTO @@ -1095,11 +1110,11 @@ 'test/fuzzers/fuzz_ClientHelloParser.cc', ], 'conditions': [ - ['OS=="linux"', { + ['OS=="linux" or OS=="openharmony"', { 'ldflags': [ '-fsanitize=fuzzer' ] }], # Ensure that ossfuzz flag has been set and that we are on Linux - [ 'OS!="linux" or ossfuzz!="true"', { + [ 'OS not in "linux openharmony" or ossfuzz!="true"', { 'type': 'none', }], # Avoid excessive LTO @@ -1140,11 +1155,11 @@ 'test/fuzzers/fuzz_strings.cc', ], 'conditions': [ - ['OS=="linux"', { + ['OS=="linux" or OS=="openharmony"', { 'ldflags': [ '-fsanitize=fuzzer' ] }], # Ensure that ossfuzz flag has been set and that we are on Linux - [ 'OS!="linux" or ossfuzz!="true"', { + [ 'OS not in "linux openharmony" or ossfuzz!="true"', { 'type': 'none', }], # Avoid excessive LTO @@ -1340,7 +1355,7 @@ [ 'node_shared_libuv=="false"', { 'dependencies': [ 'deps/uv/uv.gyp:libuv#host' ], }], - [ 'OS in "linux mac"', { + [ 'OS in "linux mac openharmony"', { 'defines': ['NODE_JS2C_USE_STRING_LITERALS'], }], [ 'debug_node=="true"', { diff --git a/node.gypi b/node.gypi index 17d09d0feb389b..5e0ccc948a6ec7 100644 --- a/node.gypi +++ b/node.gypi @@ -236,7 +236,7 @@ 'dependencies': [ 'deps/brotli/brotli.gyp:brotli' ], }], - [ 'node_shared_sqlite=="false"', { + [ 'node_use_sqlite=="true" and node_shared_sqlite=="false"', { 'dependencies': [ 'deps/sqlite/sqlite.gyp:sqlite' ], }], @@ -310,7 +310,7 @@ 'NODE_PLATFORM="sunos"', ], }], - [ '(OS=="freebsd" or OS=="linux") and node_shared=="false"' + [ '(OS=="freebsd" or OS=="linux" or OS=="openharmony") and node_shared=="false"' ' and force_load=="true"', { 'ldflags': [ '-Wl,-z,noexecstack', @@ -335,7 +335,7 @@ ], }, }], - [ 'coverage=="true" and node_shared=="false" and OS in "mac freebsd linux"', { + [ 'coverage=="true" and node_shared=="false" and OS in "mac freebsd linux openharmony"', { 'cflags!': [ '-O3' ], 'ldflags': [ '--coverage', '-g', @@ -367,12 +367,12 @@ [ 'OS=="sunos"', { 'ldflags': [ '-Wl,-M,/usr/lib/ld/map.noexstk' ], }], - [ 'OS=="linux"', { + [ 'OS=="linux" or OS=="openharmony"', { 'libraries!': [ '-lrt' ], }], - [ 'OS in "freebsd linux"', { + [ 'OS in "freebsd linux openharmony"', { 'ldflags': [ '-Wl,-z,relro', '-Wl,-z,now' ] }], @@ -404,7 +404,7 @@ }, }, 'conditions': [ - ['OS in "linux freebsd" and node_shared=="false"', { + ['OS in "linux freebsd openharmony" and node_shared=="false"', { 'ldflags': [ '-Wl,--whole-archive,' '<(obj_dir)/deps/openssl/<(openssl_product)', diff --git a/src/cares_wrap.cc b/src/cares_wrap.cc index 6290bcd37f3411..5016c3d51dac66 100644 --- a/src/cares_wrap.cc +++ b/src/cares_wrap.cc @@ -879,9 +879,9 @@ void ChannelWrap::Setup() { } /* We do the call to ares_init_option for caller. */ - const int optmask = - ARES_OPT_FLAGS | ARES_OPT_TIMEOUTMS | - ARES_OPT_SOCK_STATE_CB | ARES_OPT_TRIES; + const int optmask = ARES_OPT_FLAGS | ARES_OPT_TIMEOUTMS | + ARES_OPT_SOCK_STATE_CB | ARES_OPT_TRIES | + ARES_OPT_QUERY_CACHE; r = ares_init_options(&channel_, &options, optmask); if (r != ARES_SUCCESS) { diff --git a/src/debug_utils.cc b/src/debug_utils.cc index 8a85e066fd9e6f..97884b9a0f8d6d 100644 --- a/src/debug_utils.cc +++ b/src/debug_utils.cc @@ -471,7 +471,7 @@ std::vector NativeSymbolDebuggingContext::GetLoadedLibraries() { DWORD size_2 = 0; // First call to get the size of module array needed if (EnumProcessModules(process_handle, nullptr, 0, &size_1)) { - MallocedBuffer modules(size_1); + MallocedBuffer modules(size_1 / sizeof(HMODULE)); // Second call to populate the module array if (EnumProcessModules(process_handle, modules.data, size_1, &size_2)) { @@ -480,16 +480,15 @@ std::vector NativeSymbolDebuggingContext::GetLoadedLibraries() { i++) { WCHAR module_name[MAX_PATH]; // Obtain and report the full pathname for each module - if (GetModuleFileNameExW(process_handle, - modules.data[i], - module_name, - arraysize(module_name) / sizeof(WCHAR))) { + if (GetModuleFileNameW( + modules.data[i], module_name, arraysize(module_name))) { DWORD size = WideCharToMultiByte( CP_UTF8, 0, module_name, -1, nullptr, 0, nullptr, nullptr); char* str = new char[size]; WideCharToMultiByte( CP_UTF8, 0, module_name, -1, str, size, nullptr, nullptr); list.emplace_back(str); + delete str; } } } diff --git a/src/debug_utils.h b/src/debug_utils.h index 7f073e1ea8b37a..ab5cd08f7e4cc7 100644 --- a/src/debug_utils.h +++ b/src/debug_utils.h @@ -52,6 +52,7 @@ void NODE_EXTERN_PRIVATE FWrite(FILE* file, const std::string& str); V(NGTCP2_DEBUG) \ V(SEA) \ V(WASI) \ + V(MODULE) \ V(MKSNAPSHOT) \ V(SNAPSHOT_SERDES) \ V(PERMISSION_MODEL) \ diff --git a/src/env-inl.h b/src/env-inl.h index d4b211dfb2f77a..0d32d9f5a55da2 100644 --- a/src/env-inl.h +++ b/src/env-inl.h @@ -805,6 +805,13 @@ inline void Environment::ThrowError( isolate()->ThrowException(fun(OneByteString(isolate(), errmsg), {})); } +inline void Environment::ThrowStdErrException(std::error_code error_code, + const char* syscall, + const char* path) { + ThrowErrnoException( + error_code.value(), syscall, error_code.message().c_str(), path); +} + inline void Environment::ThrowErrnoException(int errorno, const char* syscall, const char* message, diff --git a/src/env.cc b/src/env.cc index f8c24e422756d5..99bd3e37853f99 100644 --- a/src/env.cc +++ b/src/env.cc @@ -952,6 +952,25 @@ Environment::Environment(IsolateData* isolate_data, permission()->Apply(this, {"*"}, permission::PermissionScope::kWASI); } + // Implicit allow entrypoint to kFileSystemRead + if (!options_->has_eval_string && !options_->force_repl) { + std::string first_argv; + if (argv_.size() > 1) { + first_argv = argv_[1]; + } + + // Also implicit allow preloaded modules to kFileSystemRead + if (!options_->preload_cjs_modules.empty()) { + for (const std::string& mod : options_->preload_cjs_modules) { + options_->allow_fs_read.push_back(mod); + } + } + + if (first_argv != "inspect") { + options_->allow_fs_read.push_back(first_argv); + } + } + if (!options_->allow_fs_read.empty()) { permission()->Apply(this, options_->allow_fs_read, diff --git a/src/env.h b/src/env.h index b6bdff9b8580d2..c42493ad958508 100644 --- a/src/env.h +++ b/src/env.h @@ -850,6 +850,9 @@ class Environment final : public MemoryRetainer { inline void ThrowError(const char* errmsg); inline void ThrowTypeError(const char* errmsg); inline void ThrowRangeError(const char* errmsg); + inline void ThrowStdErrException(std::error_code error_code, + const char* syscall, + const char* path = nullptr); inline void ThrowErrnoException(int errorno, const char* syscall = nullptr, const char* message = nullptr, diff --git a/src/env_properties.h b/src/env_properties.h index cbb7eab2df0416..3df4e303e05105 100644 --- a/src/env_properties.h +++ b/src/env_properties.h @@ -354,6 +354,7 @@ V(sni_context_string, "sni_context") \ V(source_string, "source") \ V(source_map_url_string, "sourceMapURL") \ + V(source_url_string, "sourceURL") \ V(specifier_string, "specifier") \ V(stack_string, "stack") \ V(standard_name_string, "standardName") \ diff --git a/src/inspector/main_thread_interface.h b/src/inspector/main_thread_interface.h index 35997adbe5ac66..3311f9df014a39 100644 --- a/src/inspector/main_thread_interface.h +++ b/src/inspector/main_thread_interface.h @@ -57,6 +57,10 @@ class MainThreadHandle : public std::enable_shared_from_this { std::unique_ptr MakeDelegateThreadSafe( std::unique_ptr delegate); bool Expired(); + void SetTargetSessionId(int target_session_id) { + target_session_id_ = target_session_id; + } + std::optional GetTargetSessionId() { return target_session_id_; } private: void Reset(); @@ -65,6 +69,7 @@ class MainThreadHandle : public std::enable_shared_from_this { Mutex block_lock_; int next_session_id_ = 0; std::atomic_int next_object_id_ = {1}; + std::optional target_session_id_ = std::nullopt; friend class MainThreadInterface; }; diff --git a/src/inspector/network_agent.cc b/src/inspector/network_agent.cc index 497260ecc93c5f..faa49ead94a698 100644 --- a/src/inspector/network_agent.cc +++ b/src/inspector/network_agent.cc @@ -15,6 +15,7 @@ using v8::Maybe; using v8::MaybeLocal; using v8::Nothing; using v8::Object; +using v8::Uint8Array; using v8::Value; // Get a protocol string property from the object. @@ -168,11 +169,23 @@ std::unique_ptr createResponseFromObject( return {}; } + protocol::String mimeType; + if (!ObjectGetProtocolString(context, response, "mimeType").To(&mimeType)) { + mimeType = protocol::String(""); + } + + protocol::String charset = protocol::String(); + if (!ObjectGetProtocolString(context, response, "charset").To(&charset)) { + charset = protocol::String(""); + } + return protocol::Network::Response::create() .setUrl(url) .setStatus(status) .setStatusText(statusText) .setHeaders(std::move(headers)) + .setMimeType(mimeType) + .setCharset(charset) .build(); } @@ -183,6 +196,7 @@ NetworkAgent::NetworkAgent(NetworkInspector* inspector, event_notifier_map_["responseReceived"] = &NetworkAgent::responseReceived; event_notifier_map_["loadingFailed"] = &NetworkAgent::loadingFailed; event_notifier_map_["loadingFinished"] = &NetworkAgent::loadingFinished; + event_notifier_map_["dataReceived"] = &NetworkAgent::dataReceived; } void NetworkAgent::emitNotification(v8::Local context, @@ -211,6 +225,30 @@ protocol::DispatchResponse NetworkAgent::disable() { return protocol::DispatchResponse::Success(); } +protocol::DispatchResponse NetworkAgent::streamResourceContent( + const protocol::String& in_requestId, protocol::Binary* out_bufferedData) { + if (!requests_.contains(in_requestId)) { + // Request not found, ignore it. + return protocol::DispatchResponse::InvalidParams("Request not found"); + } + + auto& it = requests_[in_requestId]; + + it.is_streaming = true; + + // Concat response bodies. + *out_bufferedData = protocol::Binary::concat(it.response_data_blobs); + // Clear buffered data. + it.response_data_blobs.clear(); + + if (it.is_finished) { + // If the request is finished, remove the entry. + requests_.erase(in_requestId); + } + + return protocol::DispatchResponse::Success(); +} + void NetworkAgent::requestWillBeSent(v8::Local context, v8::Local params) { protocol::String request_id; @@ -247,6 +285,12 @@ void NetworkAgent::requestWillBeSent(v8::Local context, std::move(initiator), timestamp, wall_time); + + if (requests_.contains(request_id)) { + // Duplicate entry, ignore it. + return; + } + requests_.emplace(request_id, RequestEntry{timestamp, false, false, {}}); } void NetworkAgent::responseReceived(v8::Local context, @@ -295,6 +339,8 @@ void NetworkAgent::loadingFailed(v8::Local context, } frontend_->loadingFailed(request_id, timestamp, type, error_text); + + requests_.erase(request_id); } void NetworkAgent::loadingFinished(v8::Local context, @@ -309,6 +355,63 @@ void NetworkAgent::loadingFinished(v8::Local context, } frontend_->loadingFinished(request_id, timestamp); + + auto request_entry = requests_.find(request_id); + if (request_entry == requests_.end()) { + // No entry found. Ignore it. + return; + } + + if (request_entry->second.is_streaming) { + // Streaming finished, remove the entry. + requests_.erase(request_id); + } else { + request_entry->second.is_finished = true; + } +} + +void NetworkAgent::dataReceived(v8::Local context, + v8::Local params) { + protocol::String request_id; + if (!ObjectGetProtocolString(context, params, "requestId").To(&request_id)) { + return; + } + + auto request_entry = requests_.find(request_id); + if (request_entry == requests_.end()) { + // No entry found. Ignore it. + return; + } + + double timestamp; + if (!ObjectGetDouble(context, params, "timestamp").To(×tamp)) { + return; + } + int data_length; + if (!ObjectGetInt(context, params, "dataLength").To(&data_length)) { + return; + } + int encoded_data_length; + if (!ObjectGetInt(context, params, "encodedDataLength") + .To(&encoded_data_length)) { + return; + } + Local data_obj; + if (!ObjectGetObject(context, params, "data").ToLocal(&data_obj)) { + return; + } + if (!data_obj->IsUint8Array()) { + return; + } + Local data = data_obj.As(); + auto data_bin = protocol::Binary::fromUint8Array(data); + + if (request_entry->second.is_streaming) { + frontend_->dataReceived( + request_id, timestamp, data_length, encoded_data_length, data_bin); + } else { + requests_[request_id].response_data_blobs.push_back(data_bin); + } } } // namespace inspector diff --git a/src/inspector/network_agent.h b/src/inspector/network_agent.h index 459195ad6d31c2..1229ae78044c3a 100644 --- a/src/inspector/network_agent.h +++ b/src/inspector/network_agent.h @@ -3,6 +3,7 @@ #include "node/inspector/protocol/Network.h" +#include #include namespace node { @@ -10,6 +11,13 @@ namespace inspector { class NetworkInspector; +struct RequestEntry { + double timestamp; + bool is_finished; + bool is_streaming; + std::vector response_data_blobs; +}; + class NetworkAgent : public protocol::Network::Backend { public: explicit NetworkAgent(NetworkInspector* inspector, @@ -21,6 +29,10 @@ class NetworkAgent : public protocol::Network::Backend { protocol::DispatchResponse disable() override; + protocol::DispatchResponse streamResourceContent( + const protocol::String& in_requestId, + protocol::Binary* out_bufferedData) override; + void emitNotification(v8::Local context, const protocol::String& event, v8::Local params); @@ -37,6 +49,9 @@ class NetworkAgent : public protocol::Network::Backend { void loadingFinished(v8::Local context, v8::Local params); + void dataReceived(v8::Local context, + v8::Local params); + private: NetworkInspector* inspector_; v8_inspector::V8Inspector* v8_inspector_; @@ -44,6 +59,7 @@ class NetworkAgent : public protocol::Network::Backend { using EventNotifier = void (NetworkAgent::*)(v8::Local context, v8::Local); std::unordered_map event_notifier_map_; + std::map requests_; }; } // namespace inspector diff --git a/src/inspector/node_inspector.gypi b/src/inspector/node_inspector.gypi index b789018e24f545..176663780afc95 100644 --- a/src/inspector/node_inspector.gypi +++ b/src/inspector/node_inspector.gypi @@ -32,6 +32,8 @@ 'src/inspector/network_inspector.h', 'src/inspector/network_agent.cc', 'src/inspector/network_agent.h', + 'src/inspector/target_agent.cc', + 'src/inspector/target_agent.h', 'src/inspector/worker_inspector.cc', 'src/inspector/worker_inspector.h', ], @@ -47,6 +49,8 @@ '<(SHARED_INTERMEDIATE_DIR)/src/node/inspector/protocol/NodeRuntime.h', '<(SHARED_INTERMEDIATE_DIR)/src/node/inspector/protocol/Network.cpp', '<(SHARED_INTERMEDIATE_DIR)/src/node/inspector/protocol/Network.h', + '<(SHARED_INTERMEDIATE_DIR)/src/node/inspector/protocol/Target.cpp', + '<(SHARED_INTERMEDIATE_DIR)/src/node/inspector/protocol/Target.h', ], 'node_protocol_files': [ '<(protocol_tool_path)/lib/Forward_h.template', diff --git a/src/inspector/node_protocol.pdl b/src/inspector/node_protocol.pdl index 2fe6634ad7e278..148a0debe28da1 100644 --- a/src/inspector/node_protocol.pdl +++ b/src/inspector/node_protocol.pdl @@ -173,6 +173,8 @@ experimental domain Network integer status string statusText Headers headers + string mimeType + string charset # Request / response headers as keys / values of JSON object. type Headers extends object @@ -183,6 +185,16 @@ experimental domain Network # Enables network tracking, network events will now be delivered to the client. command enable + # Enables streaming of the response for the given requestId. + # If enabled, the dataReceived event contains the data that was received during streaming. + experimental command streamResourceContent + parameters + # Identifier of the request to stream. + RequestId requestId + returns + # Data that has been buffered until streaming is enabled. + binary bufferedData + # Fired when page is about to send HTTP request. event requestWillBeSent parameters @@ -227,6 +239,20 @@ experimental domain Network # Timestamp. MonotonicTime timestamp + # Fired when data chunk was received over the network. + event dataReceived + parameters + # Request identifier. + RequestId requestId + # Timestamp. + MonotonicTime timestamp + # Data chunk length. + integer dataLength + # Actual bytes received (might be less than dataLength for compressed encodings). + integer encodedDataLength + # Data that was received. + experimental optional binary data + # Support for inspecting node process state. experimental domain NodeRuntime # Enable the NodeRuntime events except by `NodeRuntime.waitingForDisconnect`. @@ -249,3 +275,28 @@ experimental domain NodeRuntime # This event is fired when the runtime is waiting for the debugger. For # example, when inspector.waitingForDebugger is called event waitingForDebugger + +# https://chromedevtools.github.io/devtools-protocol/1-3/Target/ +experimental domain Target + type SessionID extends string + type TargetID extends string + type TargetInfo extends object + properties + TargetID targetId + string type + string title + string url + boolean attached + boolean canAccessOpener + event targetCreated + parameters + TargetInfo targetInfo + event attachedToTarget + parameters + SessionID sessionId + TargetInfo targetInfo + boolean waitingForDebugger + command setAutoAttach + parameters + boolean autoAttach + boolean waitForDebuggerOnStart diff --git a/src/inspector/node_string.cc b/src/inspector/node_string.cc index 6db4bee1072bfe..8521730bd03cdf 100644 --- a/src/inspector/node_string.cc +++ b/src/inspector/node_string.cc @@ -28,6 +28,20 @@ void ProtocolTypeTraits::Serialize(const std::string& value, cbor::EncodeString8(SpanFrom(value), bytes); } +bool ProtocolTypeTraits::Deserialize( + DeserializerState* state, node::inspector::protocol::Binary* value) { + CHECK(state->tokenizer()->TokenTag() == cbor::CBORTokenTag::BINARY); + span cbor_span = state->tokenizer()->GetBinary(); + *value = node::inspector::protocol::Binary::fromSpan(cbor_span); + return true; +} + +void ProtocolTypeTraits::Serialize( + const node::inspector::protocol::Binary& value, + std::vector* bytes) { + cbor::EncodeString8(SpanFrom(value.toBase64()), bytes); +} + } // namespace crdtp namespace node { @@ -93,6 +107,58 @@ size_t StringUtil::CharacterCount(const std::string_view s) { return s.length(); } +String Binary::toBase64() const { + MaybeStackBuffer buffer; + size_t str_len = simdutf::base64_length_from_binary(bytes_->size()); + buffer.SetLength(str_len); + + size_t len = + simdutf::binary_to_base64(reinterpret_cast(bytes_->data()), + bytes_->size(), + buffer.out()); + CHECK_EQ(len, str_len); + return buffer.ToString(); +} + +// static +Binary Binary::concat(const std::vector& binaries) { + size_t total_size = 0; + for (const auto& binary : binaries) { + total_size += binary.size(); + } + auto bytes = std::make_shared>(total_size); + uint8_t* data_ptr = bytes->data(); + for (const auto& binary : binaries) { + memcpy(data_ptr, binary.data(), binary.size()); + data_ptr += binary.size(); + } + return Binary(bytes); +} + +// static +Binary Binary::fromBase64(const String& base64, bool* success) { + Binary binary{}; + size_t base64_len = simdutf::maximal_binary_length_from_base64( + base64.data(), base64.length()); + binary.bytes_->resize(base64_len); + + simdutf::result result; + result = + simdutf::base64_to_binary(base64.data(), + base64.length(), + reinterpret_cast(binary.bytes_->data())); + CHECK_EQ(result.error, simdutf::error_code::SUCCESS); + return binary; +} + +// static +Binary Binary::fromUint8Array(v8::Local data) { + auto bytes = std::make_shared>(data->ByteLength()); + size_t size = data->CopyContents(bytes->data(), data->ByteLength()); + CHECK_EQ(size, data->ByteLength()); + return Binary(bytes); +} + } // namespace protocol } // namespace inspector } // namespace node diff --git a/src/inspector/node_string.h b/src/inspector/node_string.h index 38cf96e874dcc4..94ec9b2301998c 100644 --- a/src/inspector/node_string.h +++ b/src/inspector/node_string.h @@ -3,13 +3,17 @@ #ifndef SRC_INSPECTOR_NODE_STRING_H_ #define SRC_INSPECTOR_NODE_STRING_H_ +#include +#include +#include +#include "crdtp/maybe.h" #include "crdtp/protocol_core.h" #include "util.h" #include "v8-inspector.h" -#include -#include -#include +namespace node::inspector::protocol { +class Binary; +} namespace crdtp { @@ -19,6 +23,19 @@ struct ProtocolTypeTraits { static void Serialize(const std::string& value, std::vector* bytes); }; +template <> +struct ProtocolTypeTraits { + static bool Deserialize(DeserializerState* state, + node::inspector::protocol::Binary* value); + static void Serialize(const node::inspector::protocol::Binary& value, + std::vector* bytes); +}; + +template <> +struct detail::MaybeTypedef { + typedef ValueMaybe type; +}; + } // namespace crdtp namespace node { @@ -55,18 +72,32 @@ struct StringUtil { }; // A read-only sequence of uninterpreted bytes with reference-counted storage. -// Though the templates for generating the protocol bindings reference -// this type, js_protocol.pdl doesn't have a field of type 'binary', so -// therefore it's unnecessary to provide an implementation here. class Binary { public: - const uint8_t* data() const { UNREACHABLE(); } - size_t size() const { UNREACHABLE(); } - String toBase64() const { UNREACHABLE(); } - static Binary fromBase64(const std::string_view base64, bool* success) { - UNREACHABLE(); + Binary() : bytes_(std::make_shared>()) {} + + const uint8_t* data() const { return bytes_->data(); } + size_t size() const { return bytes_->size(); } + + String toBase64() const; + + static Binary concat(const std::vector& binaries); + + static Binary fromBase64(const String& base64, bool* success); + static Binary fromUint8Array(v8::Local data); + static Binary fromSpan(const uint8_t* data, size_t size) { + return Binary::fromSpan(crdtp::span(data, size)); + } + static Binary fromSpan(crdtp::span span) { + return Binary( + std::make_shared>(span.begin(), span.end())); } - static Binary fromSpan(const uint8_t* data, size_t size) { UNREACHABLE(); } + + private: + std::shared_ptr> bytes_; + + explicit Binary(std::shared_ptr> bytes) + : bytes_(bytes) {} }; } // namespace protocol diff --git a/src/inspector/target_agent.cc b/src/inspector/target_agent.cc new file mode 100644 index 00000000000000..2f841cb2a9c54c --- /dev/null +++ b/src/inspector/target_agent.cc @@ -0,0 +1,136 @@ +#include "target_agent.h" +#include +#include "crdtp/dispatch.h" +#include "inspector/worker_inspector.h" +#include "main_thread_interface.h" + +namespace node { +namespace inspector { +namespace protocol { + +std::unordered_map> + TargetAgent::target_session_id_worker_map_ = + std::unordered_map>(); +int TargetAgent::next_session_id_ = 1; +class WorkerTargetDelegate : public WorkerDelegate { + public: + explicit WorkerTargetDelegate(std::shared_ptr target_agent) + : target_agent_(target_agent) {} + + void WorkerCreated(const std::string& title, + const std::string& url, + bool waiting, + std::shared_ptr worker) override { + target_agent_->createAndAttachIfNecessary(worker, title, url); + } + + private: + const std::shared_ptr target_agent_; +}; + +std::unique_ptr createTargetInfo( + const std::string_view target_id, + const std::string_view type, + const std::string_view title, + const std::string_view url) { + return Target::TargetInfo::create() + .setTargetId(std::string(target_id)) + .setType(std::string(type)) + .setTitle(std::string(title)) + .setUrl(std::string(url)) + .setAttached(false) + .setCanAccessOpener(true) + .build(); +} + +void TargetAgent::Wire(UberDispatcher* dispatcher) { + frontend_ = std::make_unique(dispatcher->channel()); + Target::Dispatcher::wire(dispatcher, this); +} + +void TargetAgent::createAndAttachIfNecessary( + std::shared_ptr worker, + const std::string& title, + const std::string& url) { + std::string target_id = std::to_string(getNextTargetId()); + std::string type = "node_worker"; + + targetCreated(target_id, type, title, url); + bool attached = false; + if (auto_attach_) { + attached = true; + attachedToTarget(worker, target_id, type, title, url); + } + targets_.push_back({target_id, type, title, url, worker, attached}); +} + +void TargetAgent::listenWorker(std::weak_ptr worker_manager) { + auto manager = worker_manager.lock(); + if (!manager) { + return; + } + std::unique_ptr delegate( + new WorkerTargetDelegate(shared_from_this())); + worker_event_handle_ = manager->SetAutoAttach(std::move(delegate)); +} + +void TargetAgent::reset() { + if (worker_event_handle_) { + worker_event_handle_.reset(); + } +} + +void TargetAgent::targetCreated(const std::string_view target_id, + const std::string_view type, + const std::string_view title, + const std::string_view url) { + frontend_->targetCreated(createTargetInfo(target_id, type, title, url)); +} + +int TargetAgent::getNextSessionId() { + return next_session_id_++; +} + +int TargetAgent::getNextTargetId() { + return next_target_id_++; +} + +void TargetAgent::attachedToTarget(std::shared_ptr worker, + const std::string& target_id, + const std::string& type, + const std::string& title, + const std::string& url) { + int session_id = getNextSessionId(); + target_session_id_worker_map_[session_id] = worker; + worker->SetTargetSessionId(session_id); + frontend_->attachedToTarget(std::to_string(session_id), + createTargetInfo(target_id, type, title, url), + true); +} + +// TODO(islandryu): Currently, setAutoAttach applies the main thread's value to +// all threads. Modify it to be managed per worker thread. +crdtp::DispatchResponse TargetAgent::setAutoAttach( + bool auto_attach, bool wait_for_debugger_on_start) { + auto_attach_ = auto_attach; + wait_for_debugger_on_start_ = wait_for_debugger_on_start; + + if (auto_attach) { + for (auto& target : targets_) { + if (!target.attached) { + target.attached = true; + attachedToTarget(target.worker, + target.target_id, + target.type, + target.title, + target.url); + } + } + } + + return DispatchResponse::Success(); +} + +} // namespace protocol +} // namespace inspector +} // namespace node diff --git a/src/inspector/target_agent.h b/src/inspector/target_agent.h new file mode 100644 index 00000000000000..36a95f80dcad75 --- /dev/null +++ b/src/inspector/target_agent.h @@ -0,0 +1,75 @@ +#ifndef SRC_INSPECTOR_TARGET_AGENT_H_ +#define SRC_INSPECTOR_TARGET_AGENT_H_ + +#include +#include +#include +#include "inspector/worker_inspector.h" +#include "node/inspector/protocol/Target.h" + +namespace node { + +namespace inspector { +class TargetInspector; + +namespace protocol { + +struct TargetInfo { + std::string target_id; + std::string type; + std::string title; + std::string url; + std::shared_ptr worker; + bool attached; +}; + +class TargetAgent : public Target::Backend, + public std::enable_shared_from_this { + public: + void Wire(UberDispatcher* dispatcher); + + void createAndAttachIfNecessary(std::shared_ptr worker, + const std::string& title, + const std::string& url); + + DispatchResponse setAutoAttach(bool auto_attach, + bool wait_for_debugger_on_start) override; + + void listenWorker(std::weak_ptr worker_manager); + void reset(); + static std::unordered_map> + target_session_id_worker_map_; + + bool isThisThread(MainThreadHandle* worker) { return worker == main_thread_; } + + private: + int getNextTargetId(); + int getNextSessionId(); + void targetCreated(const std::string_view target_id, + const std::string_view type, + const std::string_view title, + const std::string_view url); + void attachedToTarget(std::shared_ptr worker, + const std::string& target_id, + const std::string& type, + const std::string& title, + const std::string& url); + + std::shared_ptr frontend_; + std::weak_ptr worker_manager_; + static int next_session_id_; + int next_target_id_ = 1; + std::unique_ptr worker_event_handle_ = nullptr; + bool auto_attach_ = false; + // TODO(islandryu): If false, implement it so that each thread does not wait + // for the worker to execute. + bool wait_for_debugger_on_start_ = true; + std::vector targets_; + MainThreadHandle* main_thread_; +}; + +} // namespace protocol +} // namespace inspector +} // namespace node + +#endif // SRC_INSPECTOR_TARGET_AGENT_H_ diff --git a/src/inspector_agent.cc b/src/inspector_agent.cc index 7c63c22112be9f..fa6eb29e6e5829 100644 --- a/src/inspector_agent.cc +++ b/src/inspector_agent.cc @@ -8,6 +8,7 @@ #include "inspector/node_string.h" #include "inspector/protocol_helper.h" #include "inspector/runtime_agent.h" +#include "inspector/target_agent.h" #include "inspector/tracing_agent.h" #include "inspector/worker_agent.h" #include "inspector/worker_inspector.h" @@ -217,9 +218,11 @@ class ChannelImpl final : public v8_inspector::V8Inspector::Channel, const std::unique_ptr& inspector, std::shared_ptr worker_manager, std::unique_ptr delegate, - std::shared_ptr main_thread_, + std::shared_ptr main_thread, bool prevent_shutdown) - : delegate_(std::move(delegate)), prevent_shutdown_(prevent_shutdown), + : delegate_(std::move(delegate)), + main_thread_(main_thread), + prevent_shutdown_(prevent_shutdown), retaining_context_(false) { session_ = inspector->connect(CONTEXT_GROUP_ID, this, @@ -238,6 +241,11 @@ class ChannelImpl final : public v8_inspector::V8Inspector::Channel, network_inspector_ = std::make_unique(env, inspector.get()); network_inspector_->Wire(node_dispatcher_.get()); + if (env->options()->experimental_worker_inspection) { + target_agent_ = std::make_shared(); + target_agent_->Wire(node_dispatcher_.get()); + target_agent_->listenWorker(worker_manager); + } } ~ChannelImpl() override { @@ -251,6 +259,9 @@ class ChannelImpl final : public v8_inspector::V8Inspector::Channel, runtime_agent_.reset(); // Dispose before the dispatchers network_inspector_->Disable(); network_inspector_.reset(); // Dispose before the dispatchers + if (target_agent_) { + target_agent_->reset(); + } } void emitNotificationFromBackend(v8::Local context, @@ -333,6 +344,15 @@ class ChannelImpl final : public v8_inspector::V8Inspector::Channel, // crdtp::FrontendChannel void FlushProtocolNotifications() override {} + std::string serializeToJSON(std::unique_ptr message) { + std::vector cbor = message->Serialize(); + std::string json; + crdtp::Status status = ConvertCBORToJSON(crdtp::SpanFrom(cbor), &json); + CHECK(status.ok()); + USE(status); + return json; + } + void sendMessageToFrontend(const StringView& message) { if (per_process::enabled_debug_list.enabled( DebugCategory::INSPECTOR_SERVER)) { @@ -341,7 +361,18 @@ class ChannelImpl final : public v8_inspector::V8Inspector::Channel, "[inspector send] %s\n", raw_message); } - delegate_->SendMessageToFrontend(message); + std::optional target_session_id = main_thread_->GetTargetSessionId(); + if (target_session_id.has_value()) { + std::string raw_message = protocol::StringUtil::StringViewToUtf8(message); + std::unique_ptr value = + protocol::DictionaryValue::cast(JsonUtil::parseJSON(raw_message)); + std::string target_session_id_str = std::to_string(*target_session_id); + value->setString("sessionId", target_session_id_str); + std::string json = serializeToJSON(std::move(value)); + delegate_->SendMessageToFrontend(Utf8ToStringView(json)->string()); + } else { + delegate_->SendMessageToFrontend(message); + } } void sendMessageToFrontend(const std::string& message) { @@ -351,24 +382,14 @@ class ChannelImpl final : public v8_inspector::V8Inspector::Channel, // crdtp::FrontendChannel void SendProtocolResponse(int callId, std::unique_ptr message) override { - std::vector cbor = message->Serialize(); - std::string json; - crdtp::Status status = ConvertCBORToJSON(crdtp::SpanFrom(cbor), &json); - DCHECK(status.ok()); - USE(status); - + std::string json = serializeToJSON(std::move(message)); sendMessageToFrontend(json); } // crdtp::FrontendChannel void SendProtocolNotification( std::unique_ptr message) override { - std::vector cbor = message->Serialize(); - std::string json; - crdtp::Status status = ConvertCBORToJSON(crdtp::SpanFrom(cbor), &json); - DCHECK(status.ok()); - USE(status); - + std::string json = serializeToJSON(std::move(message)); sendMessageToFrontend(json); } @@ -382,10 +403,12 @@ class ChannelImpl final : public v8_inspector::V8Inspector::Channel, std::unique_ptr runtime_agent_; std::unique_ptr tracing_agent_; std::unique_ptr worker_agent_; + std::shared_ptr target_agent_; std::unique_ptr network_inspector_; std::unique_ptr delegate_; std::unique_ptr session_; std::unique_ptr node_dispatcher_; + std::shared_ptr main_thread_; bool prevent_shutdown_; bool retaining_context_; }; diff --git a/src/inspector_io.cc b/src/inspector_io.cc index 4e76e529fcf341..c197d15f135fd2 100644 --- a/src/inspector_io.cc +++ b/src/inspector_io.cc @@ -4,7 +4,9 @@ #include "crypto/crypto_util.h" #include "debug_utils-inl.h" #include "inspector/main_thread_interface.h" +#include "inspector/node_json.h" #include "inspector/node_string.h" +#include "inspector/target_agent.h" #include "inspector_socket_server.h" #include "ncrypto.h" #include "node.h" @@ -218,6 +220,7 @@ class InspectorIoDelegate: public node::inspector::SocketServerDelegate { void StartSession(int session_id, const std::string& target_id) override; void MessageReceived(int session_id, const std::string& message) override; void EndSession(int session_id) override; + std::optional GetTargetSessionId(const std::string& message); std::vector GetTargetIds() override; std::string GetTargetTitle(const std::string& id) override; @@ -337,20 +340,72 @@ InspectorIoDelegate::InspectorIoDelegate( void InspectorIoDelegate::StartSession(int session_id, const std::string& target_id) { - auto session = main_thread_->Connect( - std::unique_ptr( - new IoSessionDelegate(request_queue_->handle(), session_id)), true); - if (session) { - sessions_[session_id] = std::move(session); - fprintf(stderr, "Debugger attached.\n"); + fprintf(stderr, "Debugger attached.\n"); +} + +std::optional InspectorIoDelegate::GetTargetSessionId( + const std::string& message) { + std::string_view view(message.data(), message.size()); + std::unique_ptr value = + protocol::DictionaryValue::cast(JsonUtil::parseJSON(view)); + protocol::String target_session_id; + protocol::Value* target_session_id_value = value->get("sessionId"); + if (target_session_id_value) { + target_session_id_value->asString(&target_session_id); + } + + if (!target_session_id.empty()) { + return target_session_id; } + return std::nullopt; } void InspectorIoDelegate::MessageReceived(int session_id, const std::string& message) { - auto session = sessions_.find(session_id); - if (session != sessions_.end()) + std::optional target_session_id_str = + GetTargetSessionId(message); + std::shared_ptr worker = nullptr; + int merged_session_id = session_id; + if (target_session_id_str) { + bool is_number = std::all_of(target_session_id_str->begin(), + target_session_id_str->end(), + ::isdigit); + if (is_number) { + int target_session_id = std::stoi(*target_session_id_str); + worker = protocol::TargetAgent::target_session_id_worker_map_ + [target_session_id]; + if (worker) { + merged_session_id += target_session_id << 16; + } + } + } + + auto session = sessions_.find(merged_session_id); + + if (session == sessions_.end()) { + std::unique_ptr session; + if (worker) { + session = worker->Connect( + std::unique_ptr( + new IoSessionDelegate(request_queue_->handle(), session_id)), + true); + } else { + session = main_thread_->Connect( + std::unique_ptr( + new IoSessionDelegate(request_queue_->handle(), session_id)), + true); + } + + if (session) { + sessions_[merged_session_id] = std::move(session); + sessions_[merged_session_id]->Dispatch( + Utf8ToStringView(message)->string()); + } else { + fprintf(stderr, "Failed to connect to inspector session.\n"); + } + } else { session->second->Dispatch(Utf8ToStringView(message)->string()); + } } void InspectorIoDelegate::EndSession(int session_id) { diff --git a/src/module_wrap.cc b/src/module_wrap.cc index 912acc8da81540..cdd0ba00eb0caf 100644 --- a/src/module_wrap.cc +++ b/src/module_wrap.cc @@ -305,6 +305,13 @@ void ModuleWrap::New(const FunctionCallbackInfo& args) { return; } + if (that->Set(context, + realm->env()->source_url_string(), + module->GetUnboundModuleScript()->GetSourceURL()) + .IsNothing()) { + return; + } + if (that->Set(context, realm->env()->source_map_url_string(), module->GetUnboundModuleScript()->GetSourceMappingURL()) @@ -808,6 +815,16 @@ void ModuleWrap::GetStatus(const FunctionCallbackInfo& args) { args.GetReturnValue().Set(module->GetStatus()); } +void ModuleWrap::IsGraphAsync(const FunctionCallbackInfo& args) { + Isolate* isolate = args.GetIsolate(); + ModuleWrap* obj; + ASSIGN_OR_RETURN_UNWRAP(&obj, args.This()); + + Local module = obj->module_.Get(isolate); + + args.GetReturnValue().Set(module->IsGraphAsync()); +} + void ModuleWrap::GetError(const FunctionCallbackInfo& args) { Isolate* isolate = args.GetIsolate(); ModuleWrap* obj; @@ -905,16 +922,23 @@ static MaybeLocal ImportModuleDynamically( }; Local result; - if (import_callback->Call( - context, - Undefined(isolate), - arraysize(import_args), - import_args).ToLocal(&result)) { - CHECK(result->IsPromise()); - return handle_scope.Escape(result.As()); + if (!import_callback + ->Call( + context, Undefined(isolate), arraysize(import_args), import_args) + .ToLocal(&result)) { + return {}; } - return MaybeLocal(); + // Wrap the returned value in a promise created in the referrer context to + // avoid dynamic scopes. + Local resolver; + if (!Promise::Resolver::New(context).ToLocal(&resolver)) { + return {}; + } + if (resolver->Resolve(context, result).IsNothing()) { + return {}; + } + return handle_scope.Escape(resolver->GetPromise()); } void ModuleWrap::SetImportModuleDynamicallyCallback( @@ -1157,6 +1181,7 @@ void ModuleWrap::CreatePerIsolateProperties(IsolateData* isolate_data, isolate, tpl, "createCachedData", CreateCachedData); SetProtoMethodNoSideEffect(isolate, tpl, "getNamespace", GetNamespace); SetProtoMethodNoSideEffect(isolate, tpl, "getStatus", GetStatus); + SetProtoMethodNoSideEffect(isolate, tpl, "isGraphAsync", IsGraphAsync); SetProtoMethodNoSideEffect(isolate, tpl, "getError", GetError); SetConstructorFunction(isolate, target, "ModuleWrap", tpl); isolate_data->set_module_wrap_constructor_template(tpl); @@ -1213,6 +1238,7 @@ void ModuleWrap::RegisterExternalReferences( registry->Register(GetNamespace); registry->Register(GetStatus); registry->Register(GetError); + registry->Register(IsGraphAsync); registry->Register(CreateRequiredModuleFacade); diff --git a/src/module_wrap.h b/src/module_wrap.h index 83b5793013cbc4..ef4dfd1d6b091d 100644 --- a/src/module_wrap.h +++ b/src/module_wrap.h @@ -111,6 +111,7 @@ class ModuleWrap : public BaseObject { static void Instantiate(const v8::FunctionCallbackInfo& args); static void Evaluate(const v8::FunctionCallbackInfo& args); static void GetNamespace(const v8::FunctionCallbackInfo& args); + static void IsGraphAsync(const v8::FunctionCallbackInfo& args); static void GetStatus(const v8::FunctionCallbackInfo& args); static void GetError(const v8::FunctionCallbackInfo& args); diff --git a/src/node.cc b/src/node.cc index 0fbcd55d674b1d..c0d0b734edfa72 100644 --- a/src/node.cc +++ b/src/node.cc @@ -761,9 +761,11 @@ void ResetStdio() { while (err == -1 && errno == EINTR); // NOLINT CHECK_EQ(0, pthread_sigmask(SIG_UNBLOCK, &sa, nullptr)); - // Normally we expect err == 0. But if macOS App Sandbox is enabled, - // tcsetattr will fail with err == -1 and errno == EPERM. - CHECK_IMPLIES(err != 0, err == -1 && errno == EPERM); + // We don't check the return value of tcsetattr() because it can fail + // for a number of reasons, none that we can do anything about. Examples: + // - if macOS App Sandbox is enabled, tcsetattr fails with EPERM + // - if the process group is orphaned, e.g. because the user logged out, + // tcsetattr fails with EIO } } #endif // __POSIX__ @@ -1221,10 +1223,7 @@ InitializeOncePerProcessInternal(const std::vector& args, } #endif if (!crypto::ProcessFipsOptions()) { - // XXX: ERR_GET_REASON does not return something that is - // useful as an exit code at all. - result->exit_code_ = - static_cast(ERR_GET_REASON(ERR_peek_error())); + result->exit_code_ = ExitCode::kGenericUserError; result->early_return_ = true; result->errors_.emplace_back( "OpenSSL error when trying to enable FIPS:\n" + diff --git a/src/node_api.cc b/src/node_api.cc index 5c85ef063ecd77..b708f59ef362e0 100644 --- a/src/node_api.cc +++ b/src/node_api.cc @@ -704,9 +704,9 @@ void napi_module_register_by_symbol(v8::Local exports, napi_addon_register_func init, int32_t module_api_version) { node::Environment* node_env = node::Environment::GetCurrent(context); + CHECK_NOT_NULL(node_env); std::string module_filename = ""; if (init == nullptr) { - CHECK_NOT_NULL(node_env); node_env->ThrowError("Module has no declared entry point."); return; } diff --git a/src/node_binding.cc b/src/node_binding.cc index 6c337232149ccb..aa4213c3622eab 100644 --- a/src/node_binding.cc +++ b/src/node_binding.cc @@ -74,7 +74,6 @@ V(serdes) \ V(signal_wrap) \ V(spawn_sync) \ - V(sqlite) \ V(stream_pipe) \ V(stream_wrap) \ V(string_decoder) \ @@ -93,7 +92,6 @@ V(wasi) \ V(wasm_web_api) \ V(watchdog) \ - V(webstorage) \ V(worker) \ V(zlib) @@ -103,7 +101,8 @@ NODE_BUILTIN_ICU_BINDINGS(V) \ NODE_BUILTIN_PROFILER_BINDINGS(V) \ NODE_BUILTIN_DEBUG_BINDINGS(V) \ - NODE_BUILTIN_QUIC_BINDINGS(V) + NODE_BUILTIN_QUIC_BINDINGS(V) \ + NODE_BUILTIN_SQLITE_BINDINGS(V) // This is used to load built-in bindings. Instead of using // __attribute__((constructor)), we call the _register_ diff --git a/src/node_binding.h b/src/node_binding.h index eb1364cb01a2be..611f38ef5e21cc 100644 --- a/src/node_binding.h +++ b/src/node_binding.h @@ -36,6 +36,14 @@ static_assert(static_cast(NM_F_LINKED) == #define NODE_BUILTIN_QUIC_BINDINGS(V) #endif +#if HAVE_SQLITE +#define NODE_BUILTIN_SQLITE_BINDINGS(V) \ + V(sqlite) \ + V(webstorage) +#else +#define NODE_BUILTIN_SQLITE_BINDINGS(V) +#endif + #define NODE_BINDINGS_WITH_PER_ISOLATE_INIT(V) \ V(async_wrap) \ V(blob) \ diff --git a/src/node_buffer.cc b/src/node_buffer.cc index 5bdffc0a4d7f8f..b8021c079ca6b1 100644 --- a/src/node_buffer.cc +++ b/src/node_buffer.cc @@ -1441,9 +1441,9 @@ uint32_t WriteOneByteString(const char* src, return 0; } - if (encoding == UTF8) { + if constexpr (encoding == UTF8) { return simdutf::convert_latin1_to_utf8_safe(src, src_len, dst, dst_len); - } else if (encoding == LATIN1 || encoding == ASCII) { + } else if constexpr (encoding == LATIN1 || encoding == ASCII) { const auto size = std::min(src_len, dst_len); memcpy(dst, src, size); return size; diff --git a/src/node_builtins.cc b/src/node_builtins.cc index defb657a62a031..092341dbfbabe1 100644 --- a/src/node_builtins.cc +++ b/src/node_builtins.cc @@ -145,6 +145,9 @@ BuiltinLoader::BuiltinCategories BuiltinLoader::GetBuiltinCategories() const { "sqlite", // Experimental. "sys", // Deprecated. "wasi", // Experimental. +#if !HAVE_SQLITE + "internal/webstorage", // Experimental. +#endif "internal/test/binding", "internal/v8_prof_polyfill", "internal/v8_prof_processor", }; diff --git a/src/node_config.cc b/src/node_config.cc index f6ca010ff9304f..6032bbd10f41da 100644 --- a/src/node_config.cc +++ b/src/node_config.cc @@ -48,6 +48,12 @@ static void InitConfig(Local target, READONLY_FALSE_PROPERTY(target, "isDebugBuild"); #endif // defined(DEBUG) && DEBUG +#ifdef OPENSSL_IS_BORINGSSL + READONLY_TRUE_PROPERTY(target, "openSSLIsBoringSSL"); +#else + READONLY_FALSE_PROPERTY(target, "openSSLIsBoringSSL"); +#endif // OPENSSL_IS_BORINGSSL + #if HAVE_OPENSSL READONLY_TRUE_PROPERTY(target, "hasOpenSSL"); #else diff --git a/src/node_config_file.cc b/src/node_config_file.cc index d801d935a41706..3f590b53eba3c3 100644 --- a/src/node_config_file.cc +++ b/src/node_config_file.cc @@ -23,7 +23,7 @@ std::optional ConfigReader::GetDataFromArgs( } else if (it->starts_with(flag_path)) { // Case: "--experimental-config-file=foo" if (it->size() > flag_path.size() && (*it)[flag_path.size()] == '=') { - return it->substr(flag_path.size() + 1); + return std::string_view(*it).substr(flag_path.size() + 1); } } else if (*it == default_file || it->starts_with(default_file)) { has_default_config_file = true; @@ -59,8 +59,12 @@ ParseResult ConfigReader::ParseNodeOptions( FPrintF(stderr, "Invalid value for %s\n", it->first.c_str()); return ParseResult::InvalidContent; } - node_options_.push_back(it->first + "=" + - (result ? "true" : "false")); + + if (result) { + // If the value is true, we need to set the flag + node_options_.push_back(it->first); + } + break; } // String array can allow both string and array types diff --git a/src/node_constants.cc b/src/node_constants.cc index 13263149c111be..8c44e32381a446 100644 --- a/src/node_constants.cc +++ b/src/node_constants.cc @@ -1040,7 +1040,7 @@ void DefineCryptoConstants(Local target) { #endif } -void DefineSystemConstants(Local target) { +void DefineFsConstants(Local target) { NODE_DEFINE_CONSTANT(target, UV_FS_SYMLINK_DIR); NODE_DEFINE_CONSTANT(target, UV_FS_SYMLINK_JUNCTION); // file access modes @@ -1058,10 +1058,6 @@ void DefineSystemConstants(Local target) { NODE_DEFINE_CONSTANT(target, UV_DIRENT_CHAR); NODE_DEFINE_CONSTANT(target, UV_DIRENT_BLOCK); - // Define module specific constants - NODE_DEFINE_CONSTANT(target, EXTENSIONLESS_FORMAT_JAVASCRIPT); - NODE_DEFINE_CONSTANT(target, EXTENSIONLESS_FORMAT_WASM); - NODE_DEFINE_CONSTANT(target, S_IFMT); NODE_DEFINE_CONSTANT(target, S_IFREG); NODE_DEFINE_CONSTANT(target, S_IFDIR); @@ -1249,6 +1245,12 @@ void DefineDLOpenConstants(Local target) { #endif } +void DefineInternalConstants(Local target) { + // Define module specific constants + NODE_DEFINE_CONSTANT(target, EXTENSIONLESS_FORMAT_JAVASCRIPT); + NODE_DEFINE_CONSTANT(target, EXTENSIONLESS_FORMAT_WASM); +} + void DefineTraceConstants(Local target) { NODE_DEFINE_CONSTANT(target, TRACE_EVENT_PHASE_BEGIN); NODE_DEFINE_CONSTANT(target, TRACE_EVENT_PHASE_END); @@ -1323,15 +1325,20 @@ void CreatePerContextProperties(Local target, CHECK(trace_constants->SetPrototype(env->context(), Null(env->isolate())).FromJust()); + Local internal_constants = Object::New(isolate); + CHECK(internal_constants->SetPrototype(env->context(), + Null(env->isolate())).FromJust()); + DefineErrnoConstants(err_constants); DefineWindowsErrorConstants(err_constants); DefineSignalConstants(sig_constants); DefinePriorityConstants(priority_constants); - DefineSystemConstants(fs_constants); + DefineFsConstants(fs_constants); DefineCryptoConstants(crypto_constants); DefineZlibConstants(zlib_constants); DefineDLOpenConstants(dlopen_constants); DefineTraceConstants(trace_constants); + DefineInternalConstants(internal_constants); // Define libuv constants. NODE_DEFINE_CONSTANT(os_constants, UV_UDP_REUSEADDR); @@ -1377,6 +1384,11 @@ void CreatePerContextProperties(Local target, FIXED_ONE_BYTE_STRING(isolate, "trace"), trace_constants) .Check(); + target + ->Set(env->context(), + FIXED_ONE_BYTE_STRING(isolate, "internal"), + internal_constants) + .Check(); } } // namespace constants diff --git a/src/node_contextify.cc b/src/node_contextify.cc index 5bd30f6e33abbb..7bfe42c593943f 100644 --- a/src/node_contextify.cc +++ b/src/node_contextify.cc @@ -371,13 +371,11 @@ void ContextifyContext::CreatePerIsolateProperties( IsolateData* isolate_data, Local target) { Isolate* isolate = isolate_data->isolate(); SetMethod(isolate, target, "makeContext", MakeContext); - SetMethod(isolate, target, "compileFunction", CompileFunction); } void ContextifyContext::RegisterExternalReferences( ExternalReferenceRegistry* registry) { registry->Register(MakeContext); - registry->Register(CompileFunction); registry->Register(PropertyQueryCallback); registry->Register(PropertyGetterCallback); registry->Register(PropertySetterCallback); @@ -1109,6 +1107,13 @@ void ContextifyScript::New(const FunctionCallbackInfo& args) { return; } + if (args.This() + ->Set(env->context(), + env->source_url_string(), + v8_script->GetSourceURL()) + .IsNothing()) + return; + if (args.This() ->Set(env->context(), env->source_map_url_string(), @@ -1161,22 +1166,6 @@ Maybe StoreCodeCacheResult( return JustVoid(); } -// TODO(RaisinTen): Reuse in ContextifyContext::CompileFunction(). -MaybeLocal CompileFunction(Local context, - Local filename, - Local content, - LocalVector* parameters) { - ScriptOrigin script_origin(filename, 0, 0, true); - ScriptCompiler::Source script_source(content, script_origin); - - return ScriptCompiler::CompileFunction(context, - &script_source, - parameters->size(), - parameters->data(), - 0, - nullptr); -} - bool ContextifyScript::InstanceOf(Environment* env, const Local& value) { return !value.IsEmpty() && @@ -1382,7 +1371,19 @@ ContextifyScript::ContextifyScript(Environment* env, Local object) ContextifyScript::~ContextifyScript() {} -void ContextifyContext::CompileFunction( +void ContextifyFunction::RegisterExternalReferences( + ExternalReferenceRegistry* registry) { + registry->Register(CompileFunction); +} + +void ContextifyFunction::CreatePerIsolateProperties( + IsolateData* isolate_data, Local target) { + Isolate* isolate = isolate_data->isolate(); + + SetMethod(isolate, target, "compileFunction", CompileFunction); +} + +void ContextifyFunction::CompileFunction( const FunctionCallbackInfo& args) { Environment* env = Environment::GetCurrent(args); Isolate* isolate = env->isolate(); @@ -1501,24 +1502,22 @@ void ContextifyContext::CompileFunction( } TryCatchScope try_catch(env); - Local result = CompileFunctionAndCacheResult(env, - parsing_context, - &source, - params, - context_extensions, - options, - produce_cached_data, - id_symbol, - try_catch); - - if (try_catch.HasCaught() && !try_catch.HasTerminated()) { + MaybeLocal maybe_result = + CompileFunctionAndCacheResult(env, + parsing_context, + &source, + params, + context_extensions, + options, + produce_cached_data, + id_symbol, + try_catch); + Local result; + if (!maybe_result.ToLocal(&result)) { + CHECK(try_catch.HasCaught()); try_catch.ReThrow(); return; } - - if (result.IsEmpty()) { - return; - } args.GetReturnValue().Set(result); } @@ -1534,7 +1533,7 @@ static LocalVector GetCJSParameters(IsolateData* data) { return result; } -Local ContextifyContext::CompileFunctionAndCacheResult( +MaybeLocal ContextifyFunction::CompileFunctionAndCacheResult( Environment* env, Local parsing_context, ScriptCompiler::Source* source, @@ -1556,28 +1555,40 @@ Local ContextifyContext::CompileFunctionAndCacheResult( Local fn; if (!maybe_fn.ToLocal(&fn)) { - if (try_catch.HasCaught() && !try_catch.HasTerminated()) { + CHECK(try_catch.HasCaught()); + if (!try_catch.HasTerminated()) { errors::DecorateErrorStack(env, try_catch); - return Object::New(env->isolate()); } + return {}; } Local context = env->context(); if (fn->SetPrivate(context, env->host_defined_option_symbol(), id_symbol) .IsNothing()) { - return Object::New(env->isolate()); + return {}; } Isolate* isolate = env->isolate(); Local result = Object::New(isolate); if (result->Set(parsing_context, env->function_string(), fn).IsNothing()) - return Object::New(env->isolate()); + return {}; + + // ScriptOrigin::ResourceName() returns SourceURL magic comment content if + // present. + if (result + ->Set(parsing_context, + env->source_url_string(), + fn->GetScriptOrigin().ResourceName()) + .IsNothing()) { + return {}; + } if (result ->Set(parsing_context, env->source_map_url_string(), fn->GetScriptOrigin().SourceMapUrl()) - .IsNothing()) - return Object::New(env->isolate()); + .IsNothing()) { + return {}; + } std::unique_ptr new_cached_data; if (produce_cached_data) { @@ -1590,7 +1601,7 @@ Local ContextifyContext::CompileFunctionAndCacheResult( produce_cached_data, std::move(new_cached_data)) .IsNothing()) { - return Object::New(env->isolate()); + return {}; } return result; @@ -1815,12 +1826,16 @@ static void CompileFunctionForCJSLoader( Local names[] = { env->cached_data_rejected_string(), env->source_map_url_string(), + env->source_url_string(), env->function_string(), FIXED_ONE_BYTE_STRING(isolate, "canParseAsESM"), }; Local values[] = { Boolean::New(isolate, cache_rejected), fn.IsEmpty() ? undefined : fn->GetScriptOrigin().SourceMapUrl(), + // ScriptOrigin::ResourceName() returns SourceURL magic comment content if + // present. + fn.IsEmpty() ? undefined : fn->GetScriptOrigin().ResourceName(), fn.IsEmpty() ? undefined : fn.As(), Boolean::New(isolate, can_parse_as_esm), }; @@ -1874,21 +1889,6 @@ bool ShouldRetryAsESM(Realm* realm, return false; } -static void ShouldRetryAsESM(const FunctionCallbackInfo& args) { - Realm* realm = Realm::GetCurrent(args); - - CHECK_EQ(args.Length(), 3); // message, code, resource_name - CHECK(args[0]->IsString()); - Local message = args[0].As(); - CHECK(args[1]->IsString()); - Local code = args[1].As(); - CHECK(args[2]->IsString()); - Local resource_name = args[2].As(); - - args.GetReturnValue().Set( - ShouldRetryAsESM(realm, message, code, resource_name)); -} - static void ContainsModuleSyntax(const FunctionCallbackInfo& args) { Isolate* isolate = args.GetIsolate(); Local context = isolate->GetCurrentContext(); @@ -1979,6 +1979,7 @@ void CreatePerIsolateProperties(IsolateData* isolate_data, ContextifyContext::CreatePerIsolateProperties(isolate_data, target); ContextifyScript::CreatePerIsolateProperties(isolate_data, target); + ContextifyFunction::CreatePerIsolateProperties(isolate_data, target); SetMethod(isolate, target, "startSigintWatchdog", StartSigintWatchdog); SetMethod(isolate, target, "stopSigintWatchdog", StopSigintWatchdog); @@ -1993,7 +1994,6 @@ void CreatePerIsolateProperties(IsolateData* isolate_data, CompileFunctionForCJSLoader); SetMethod(isolate, target, "containsModuleSyntax", ContainsModuleSyntax); - SetMethod(isolate, target, "shouldRetryAsESM", ShouldRetryAsESM); } static void CreatePerContextProperties(Local target, @@ -2032,6 +2032,7 @@ static void CreatePerContextProperties(Local target, void RegisterExternalReferences(ExternalReferenceRegistry* registry) { ContextifyContext::RegisterExternalReferences(registry); ContextifyScript::RegisterExternalReferences(registry); + ContextifyFunction::RegisterExternalReferences(registry); registry->Register(CompileFunctionForCJSLoader); registry->Register(StartSigintWatchdog); @@ -2039,7 +2040,6 @@ void RegisterExternalReferences(ExternalReferenceRegistry* registry) { registry->Register(WatchdogHasPendingSigint); registry->Register(MeasureMemory); registry->Register(ContainsModuleSyntax); - registry->Register(ShouldRetryAsESM); } } // namespace contextify } // namespace node diff --git a/src/node_contextify.h b/src/node_contextify.h index 29ab7955dbe7d2..3a02f083c267ab 100644 --- a/src/node_contextify.h +++ b/src/node_contextify.h @@ -86,18 +86,6 @@ class ContextifyContext : public BaseObject { static bool IsStillInitializing(const ContextifyContext* ctx); static void MakeContext(const v8::FunctionCallbackInfo& args); static void IsContext(const v8::FunctionCallbackInfo& args); - static void CompileFunction( - const v8::FunctionCallbackInfo& args); - static v8::Local CompileFunctionAndCacheResult( - Environment* env, - v8::Local parsing_context, - v8::ScriptCompiler::Source* source, - v8::LocalVector params, - v8::LocalVector context_extensions, - v8::ScriptCompiler::CompileOptions options, - bool produce_cached_data, - v8::Local id_symbol, - const errors::TryCatchScope& try_catch); static v8::Intercepted PropertyQueryCallback( v8::Local property, const v8::PropertyCallbackInfo& args); @@ -177,6 +165,29 @@ class ContextifyScript : public BaseObject { v8::Global script_; }; +class ContextifyFunction final { + public: + static void RegisterExternalReferences(ExternalReferenceRegistry* registry); + static void CreatePerIsolateProperties(IsolateData* isolate_data, + v8::Local target); + + static void CompileFunction(const v8::FunctionCallbackInfo& args); + static v8::MaybeLocal CompileFunctionAndCacheResult( + Environment* env, + v8::Local parsing_context, + v8::ScriptCompiler::Source* source, + v8::LocalVector params, + v8::LocalVector context_extensions, + v8::ScriptCompiler::CompileOptions options, + bool produce_cached_data, + v8::Local id_symbol, + const errors::TryCatchScope& try_catch); + + private: + ContextifyFunction() = delete; + ~ContextifyFunction() = delete; +}; + v8::Maybe StoreCodeCacheResult( Environment* env, v8::Local target, @@ -185,12 +196,6 @@ v8::Maybe StoreCodeCacheResult( bool produce_cached_data, std::unique_ptr new_cached_data); -v8::MaybeLocal CompileFunction( - v8::Local context, - v8::Local filename, - v8::Local content, - v8::LocalVector* parameters); - } // namespace contextify } // namespace node diff --git a/src/node_dotenv.cc b/src/node_dotenv.cc index d5f14fa92e2694..3bdeaab1a9cb23 100644 --- a/src/node_dotenv.cc +++ b/src/node_dotenv.cc @@ -65,18 +65,19 @@ std::vector Dotenv::GetDataFromArgs( } Maybe Dotenv::SetEnvironment(node::Environment* env) { - Local name; - Local val; auto context = env->context(); + auto env_vars = env->env_vars(); for (const auto& entry : store_) { - auto existing = env->env_vars()->Get(entry.first.data()); + auto existing = env_vars->Get(entry.first.data()); if (!existing.has_value()) { + Local name; + Local val; if (!ToV8Value(context, entry.first).ToLocal(&name) || !ToV8Value(context, entry.second).ToLocal(&val)) { return Nothing(); } - env->env_vars()->Set(env->isolate(), name.As(), val.As()); + env_vars->Set(env->isolate(), name.As(), val.As()); } } diff --git a/src/node_errors.h b/src/node_errors.h index f813c5b38766d8..8b8df1bded550b 100644 --- a/src/node_errors.h +++ b/src/node_errors.h @@ -78,7 +78,9 @@ void OOMErrorHandler(const char* location, const v8::OOMDetails& details); V(ERR_FS_CP_EINVAL, Error) \ V(ERR_FS_CP_DIR_TO_NON_DIR, Error) \ V(ERR_FS_CP_NON_DIR_TO_DIR, Error) \ + V(ERR_FS_CP_SYMLINK_TO_SUBDIRECTORY, Error) \ V(ERR_FS_EISDIR, Error) \ + V(ERR_FS_CP_EEXIST, Error) \ V(ERR_FS_CP_SOCKET, Error) \ V(ERR_FS_CP_FIFO_PIPE, Error) \ V(ERR_FS_CP_UNKNOWN, Error) \ diff --git a/src/node_external_reference.h b/src/node_external_reference.h index bb007dbdcce486..3bc7b2cab5a12e 100644 --- a/src/node_external_reference.h +++ b/src/node_external_reference.h @@ -58,6 +58,8 @@ using CFunctionCallbackWithUint8ArrayUint32Int64Bool = bool); using CFunctionWithUint32 = uint32_t (*)(v8::Local, const uint32_t input); +using CFunctionWithReturnUint32 = uint32_t (*)(v8::Local); +using CFunctionWithReturnDouble = double (*)(v8::Local); using CFunctionWithDoubleReturnDouble = double (*)(v8::Local, v8::Local, const double); @@ -96,6 +98,7 @@ class ExternalReferenceRegistry { V(CFunctionCallbackReturnBool) \ V(CFunctionCallbackReturnDouble) \ V(CFunctionCallbackReturnInt32) \ + V(CFunctionWithReturnUint32) \ V(CFunctionCallbackValueReturnDouble) \ V(CFunctionCallbackValueReturnDoubleUnusedReceiver) \ V(CFunctionCallbackWithInt64) \ diff --git a/src/node_file.cc b/src/node_file.cc index 49816349d8bab3..fe28c340c9b503 100644 --- a/src/node_file.cc +++ b/src/node_file.cc @@ -42,6 +42,9 @@ #include "uv.h" #include "v8-fast-api-calls.h" +#include +#include +#include #include #if defined(__MINGW32__) || defined(_MSC_VER) @@ -3236,6 +3239,289 @@ static void CpSyncCheckPaths(const FunctionCallbackInfo& args) { } } +static void CpSyncOverrideFile(const FunctionCallbackInfo& args) { + Environment* env = Environment::GetCurrent(args); + Isolate* isolate = env->isolate(); + + CHECK_EQ(args.Length(), 4); // src, dest, mode, preserveTimestamps + + BufferValue src(isolate, args[0]); + CHECK_NOT_NULL(*src); + ToNamespacedPath(env, &src); + + BufferValue dest(isolate, args[1]); + CHECK_NOT_NULL(*dest); + ToNamespacedPath(env, &dest); + + int mode; + if (!GetValidFileMode(env, args[2], UV_FS_COPYFILE).To(&mode)) { + return; + } + + bool preserve_timestamps = args[3]->IsTrue(); + + THROW_IF_INSUFFICIENT_PERMISSIONS( + env, permission::PermissionScope::kFileSystemRead, src.ToStringView()); + THROW_IF_INSUFFICIENT_PERMISSIONS( + env, permission::PermissionScope::kFileSystemWrite, dest.ToStringView()); + + std::error_code error; + + if (!std::filesystem::remove(*dest, error)) { + return env->ThrowStdErrException(error, "unlink", *dest); + } + + if (mode == 0) { + // if no mode is specified use the faster std::filesystem API + if (!std::filesystem::copy_file(*src, *dest, error)) { + return env->ThrowStdErrException(error, "cp", *dest); + } + } else { + uv_fs_t req; + auto cleanup = OnScopeLeave([&req]() { uv_fs_req_cleanup(&req); }); + auto result = uv_fs_copyfile(nullptr, &req, *src, *dest, mode, nullptr); + if (is_uv_error(result)) { + return env->ThrowUVException(result, "cp", nullptr, *src, *dest); + } + } + + if (preserve_timestamps) { + uv_fs_t req; + auto cleanup = OnScopeLeave([&req]() { uv_fs_req_cleanup(&req); }); + int result = uv_fs_stat(nullptr, &req, *src, nullptr); + if (is_uv_error(result)) { + return env->ThrowUVException(result, "stat", nullptr, *src); + } + + const uv_stat_t* const s = static_cast(req.ptr); + const double source_atime = s->st_atim.tv_sec + s->st_atim.tv_nsec / 1e9; + const double source_mtime = s->st_mtim.tv_sec + s->st_mtim.tv_nsec / 1e9; + + int utime_result = + uv_fs_utime(nullptr, &req, *dest, source_atime, source_mtime, nullptr); + if (is_uv_error(utime_result)) { + return env->ThrowUVException(utime_result, "utime", nullptr, *dest); + } + } +} + +std::vector normalizePathToArray( + const std::filesystem::path& path) { + std::vector parts; + std::filesystem::path absPath = std::filesystem::absolute(path); + for (const auto& part : absPath) { + if (!part.empty()) parts.push_back(part.string()); + } + return parts; +} + +bool isInsideDir(const std::filesystem::path& src, + const std::filesystem::path& dest) { + auto srcArr = normalizePathToArray(src); + auto destArr = normalizePathToArray(dest); + if (srcArr.size() > destArr.size()) return false; + return std::equal(srcArr.begin(), srcArr.end(), destArr.begin()); +} + +static void CpSyncCopyDir(const FunctionCallbackInfo& args) { + CHECK_EQ(args.Length(), 7); // src, dest, force, dereference, errorOnExist, + // verbatimSymlinks, preserveTimestamps + + Environment* env = Environment::GetCurrent(args); + Isolate* isolate = env->isolate(); + + BufferValue src(isolate, args[0]); + CHECK_NOT_NULL(*src); + ToNamespacedPath(env, &src); + + BufferValue dest(isolate, args[1]); + CHECK_NOT_NULL(*dest); + ToNamespacedPath(env, &dest); + + bool force = args[2]->IsTrue(); + bool dereference = args[3]->IsTrue(); + bool error_on_exist = args[4]->IsTrue(); + bool verbatim_symlinks = args[5]->IsTrue(); + bool preserve_timestamps = args[6]->IsTrue(); + + std::error_code error; + std::filesystem::create_directories(*dest, error); + if (error) { + return env->ThrowStdErrException(error, "cp", *dest); + } + + auto file_copy_opts = std::filesystem::copy_options::recursive; + if (force) { + file_copy_opts |= std::filesystem::copy_options::overwrite_existing; + } else if (error_on_exist) { + file_copy_opts |= std::filesystem::copy_options::none; + } else { + file_copy_opts |= std::filesystem::copy_options::skip_existing; + } + + std::function + copy_dir_contents; + copy_dir_contents = [verbatim_symlinks, + ©_dir_contents, + &env, + file_copy_opts, + preserve_timestamps, + force, + error_on_exist, + dereference, + &isolate](std::filesystem::path src, + std::filesystem::path dest) { + std::error_code error; + for (auto dir_entry : std::filesystem::directory_iterator(src)) { + auto dest_file_path = dest / dir_entry.path().filename(); + auto dest_str = PathToString(dest); + + if (dir_entry.is_symlink()) { + if (verbatim_symlinks) { + std::filesystem::copy_symlink( + dir_entry.path(), dest_file_path, error); + if (error) { + env->ThrowStdErrException(error, "cp", dest_str.c_str()); + return false; + } + } else { + auto symlink_target = + std::filesystem::read_symlink(dir_entry.path().c_str(), error); + if (error) { + env->ThrowStdErrException(error, "cp", dest_str.c_str()); + return false; + } + + if (std::filesystem::exists(dest_file_path)) { + if (std::filesystem::is_symlink((dest_file_path.c_str()))) { + auto current_dest_symlink_target = + std::filesystem::read_symlink(dest_file_path.c_str(), error); + if (error) { + env->ThrowStdErrException(error, "cp", dest_str.c_str()); + return false; + } + + if (!dereference && + std::filesystem::is_directory(symlink_target) && + isInsideDir(symlink_target, current_dest_symlink_target)) { + std::string message = + "Cannot copy %s to a subdirectory of self %s"; + THROW_ERR_FS_CP_EINVAL(env, + message.c_str(), + symlink_target.c_str(), + current_dest_symlink_target.c_str()); + return false; + } + + // Prevent copy if src is a subdir of dest since unlinking + // dest in this case would result in removing src contents + // and therefore a broken symlink would be created. + if (std::filesystem::is_directory(dest_file_path) && + isInsideDir(current_dest_symlink_target, symlink_target)) { + std::string message = "cannot overwrite %s with %s"; + THROW_ERR_FS_CP_SYMLINK_TO_SUBDIRECTORY( + env, + message.c_str(), + current_dest_symlink_target.c_str(), + symlink_target.c_str()); + return false; + } + + // symlinks get overridden by cp even if force: false, this is + // being applied here for backward compatibility, but is it + // correct? or is it a bug? + std::filesystem::remove(dest_file_path, error); + if (error) { + env->ThrowStdErrException(error, "cp", dest_str.c_str()); + return false; + } + } else if (std::filesystem::is_regular_file(dest_file_path)) { + if (!dereference || (!force && error_on_exist)) { + auto dest_file_path_str = PathToString(dest_file_path); + env->ThrowStdErrException( + std::make_error_code(std::errc::file_exists), + "cp", + dest_file_path_str.c_str()); + return false; + } + } + } + auto symlink_target_absolute = std::filesystem::weakly_canonical( + std::filesystem::absolute(src / symlink_target)); + if (dir_entry.is_directory()) { + std::filesystem::create_directory_symlink( + symlink_target_absolute, dest_file_path, error); + } else { + std::filesystem::create_symlink( + symlink_target_absolute, dest_file_path, error); + } + if (error) { + env->ThrowStdErrException(error, "cp", dest_str.c_str()); + return false; + } + } + } else if (dir_entry.is_directory()) { + auto entry_dir_path = src / dir_entry.path().filename(); + std::filesystem::create_directory(dest_file_path); + auto success = copy_dir_contents(entry_dir_path, dest_file_path); + if (!success) { + return false; + } + } else if (dir_entry.is_regular_file()) { + std::filesystem::copy_file( + dir_entry.path(), dest_file_path, file_copy_opts, error); + if (error) { + if (error.value() == EEXIST) { + THROW_ERR_FS_CP_EEXIST(isolate, + "[ERR_FS_CP_EEXIST]: Target already exists: " + "cp returned EEXIST (%s already exists)", + dest_file_path.c_str()); + return false; + } + env->ThrowStdErrException(error, "cp", dest_str.c_str()); + return false; + } + + if (preserve_timestamps) { + uv_fs_t req; + auto cleanup = OnScopeLeave([&req]() { uv_fs_req_cleanup(&req); }); + + auto dir_entry_path_str = PathToString(dir_entry.path()); + int result = + uv_fs_stat(nullptr, &req, dir_entry_path_str.c_str(), nullptr); + if (is_uv_error(result)) { + env->ThrowUVException( + result, "stat", nullptr, dir_entry_path_str.c_str()); + return false; + } + + const uv_stat_t* const s = static_cast(req.ptr); + const double source_atime = + s->st_atim.tv_sec + s->st_atim.tv_nsec / 1e9; + const double source_mtime = + s->st_mtim.tv_sec + s->st_mtim.tv_nsec / 1e9; + + auto dest_file_path_str = PathToString(dest_file_path); + int utime_result = uv_fs_utime(nullptr, + &req, + dest_file_path_str.c_str(), + source_atime, + source_mtime, + nullptr); + if (is_uv_error(utime_result)) { + env->ThrowUVException( + utime_result, "utime", nullptr, dest_file_path_str.c_str()); + return false; + } + } + } + } + return true; + }; + + copy_dir_contents(std::filesystem::path(*src), std::filesystem::path(*dest)); +} + BindingData::FilePathIsFileReturnType BindingData::FilePathIsFile( Environment* env, const std::string& file_path) { THROW_IF_INSUFFICIENT_PERMISSIONS( @@ -3574,6 +3860,8 @@ static void CreatePerIsolateProperties(IsolateData* isolate_data, SetMethod(isolate, target, "mkdtemp", Mkdtemp); SetMethod(isolate, target, "cpSyncCheckPaths", CpSyncCheckPaths); + SetMethod(isolate, target, "cpSyncOverrideFile", CpSyncOverrideFile); + SetMethod(isolate, target, "cpSyncCopyDir", CpSyncCopyDir); StatWatcher::CreatePerIsolateProperties(isolate_data, target); BindingData::CreatePerIsolateProperties(isolate_data, target); @@ -3685,6 +3973,8 @@ void RegisterExternalReferences(ExternalReferenceRegistry* registry) { registry->Register(CopyFile); registry->Register(CpSyncCheckPaths); + registry->Register(CpSyncOverrideFile); + registry->Register(CpSyncCopyDir); registry->Register(Chmod); registry->Register(FChmod); diff --git a/src/node_http2.cc b/src/node_http2.cc index f9dfa9e7a24483..8237c9b7d325dd 100644 --- a/src/node_http2.cc +++ b/src/node_http2.cc @@ -158,6 +158,12 @@ Http2Options::Http2Options(Http2State* http2_state, SessionType type) { buffer[IDX_OPTIONS_PEER_MAX_CONCURRENT_STREAMS]); } + // Validate headers in accordance to RFC-9113 + if (flags & (1 << IDX_OPTIONS_STRICT_HTTP_FIELD_WHITESPACE_VALIDATION)) { + nghttp2_option_set_no_rfc9113_leading_and_trailing_ws_validation( + option, buffer[IDX_OPTIONS_STRICT_HTTP_FIELD_WHITESPACE_VALIDATION]); + } + // The padding strategy sets the mechanism by which we determine how much // additional frame padding to apply to DATA and HEADERS frames. Currently // this is set on a per-session basis, but eventually we may switch to diff --git a/src/node_http2_state.h b/src/node_http2_state.h index 2957a2827f370e..914ad011e021f1 100644 --- a/src/node_http2_state.h +++ b/src/node_http2_state.h @@ -60,6 +60,7 @@ namespace http2 { IDX_OPTIONS_MAX_SETTINGS, IDX_OPTIONS_STREAM_RESET_RATE, IDX_OPTIONS_STREAM_RESET_BURST, + IDX_OPTIONS_STRICT_HTTP_FIELD_WHITESPACE_VALIDATION, IDX_OPTIONS_FLAGS }; diff --git a/src/node_http_common.h b/src/node_http_common.h index e2e13e9972f9ce..5afb6b97becc4d 100644 --- a/src/node_http_common.h +++ b/src/node_http_common.h @@ -240,7 +240,7 @@ enum http_status_codes { V(VERSION_CONTROL, "VERSION-CONTROL") // NgHeaders takes as input a block of headers provided by the -// JavaScript side (see http2's mapToHeaders function) and +// JavaScript side (see http2's buildNgHeaderString function) and // converts it into a array of ng header structs. This is done // generically to handle both http/2 and (in the future) http/3, // which use nearly identical structs. The template parameter diff --git a/src/node_http_parser.cc b/src/node_http_parser.cc index 6ea4aa826e1c30..b33beecaebe8b0 100644 --- a/src/node_http_parser.cc +++ b/src/node_http_parser.cc @@ -563,7 +563,7 @@ class Parser : public AsyncWrap, public StreamListener { new Parser(binding_data, args.This()); } - + // TODO(@anonrig): Add V8 Fast API static void Close(const FunctionCallbackInfo& args) { Parser* parser; ASSIGN_OR_RETURN_UNWRAP(&parser, args.This()); @@ -571,7 +571,7 @@ class Parser : public AsyncWrap, public StreamListener { delete parser; } - + // TODO(@anonrig): Add V8 Fast API static void Free(const FunctionCallbackInfo& args) { Parser* parser; ASSIGN_OR_RETURN_UNWRAP(&parser, args.This()); @@ -582,6 +582,7 @@ class Parser : public AsyncWrap, public StreamListener { parser->EmitDestroy(); } + // TODO(@anonrig): Add V8 Fast API static void Remove(const FunctionCallbackInfo& args) { Parser* parser; ASSIGN_OR_RETURN_UNWRAP(&parser, args.This()); @@ -694,6 +695,7 @@ class Parser : public AsyncWrap, public StreamListener { } } + // TODO(@anonrig): Add V8 Fast API template static void Pause(const FunctionCallbackInfo& args) { Environment* env = Environment::GetCurrent(args); @@ -709,7 +711,7 @@ class Parser : public AsyncWrap, public StreamListener { } } - + // TODO(@anonrig): Add V8 Fast API static void Consume(const FunctionCallbackInfo& args) { Parser* parser; ASSIGN_OR_RETURN_UNWRAP(&parser, args.This()); @@ -719,7 +721,7 @@ class Parser : public AsyncWrap, public StreamListener { stream->PushStreamListener(parser); } - + // TODO(@anonrig): Add V8 Fast API static void Unconsume(const FunctionCallbackInfo& args) { Parser* parser; ASSIGN_OR_RETURN_UNWRAP(&parser, args.This()); @@ -744,26 +746,6 @@ class Parser : public AsyncWrap, public StreamListener { args.GetReturnValue().Set(ret); } - static void Duration(const FunctionCallbackInfo& args) { - Parser* parser; - ASSIGN_OR_RETURN_UNWRAP(&parser, args.This()); - - if (parser->last_message_start_ == 0) { - args.GetReturnValue().Set(0); - return; - } - - double duration = (uv_hrtime() - parser->last_message_start_) / 1e6; - args.GetReturnValue().Set(duration); - } - - static void HeadersCompleted(const FunctionCallbackInfo& args) { - Parser* parser; - ASSIGN_OR_RETURN_UNWRAP(&parser, args.This()); - - args.GetReturnValue().Set(parser->headers_completed_); - } - protected: static const size_t kAllocBufferSize = 64 * 1024; @@ -1203,6 +1185,10 @@ void ConnectionsList::Expired(const FunctionCallbackInfo& args) { const llhttp_settings_t Parser::settings = { Proxy::Raw, + + // on_protocol + nullptr, + Proxy::Raw, Proxy::Raw, @@ -1222,6 +1208,8 @@ const llhttp_settings_t Parser::settings = { Proxy::Raw, Proxy::Raw, + // on_protocol_complete + nullptr, // on_url_complete nullptr, // on_status_complete @@ -1310,8 +1298,6 @@ void CreatePerIsolateProperties(IsolateData* isolate_data, SetProtoMethod(isolate, t, "consume", Parser::Consume); SetProtoMethod(isolate, t, "unconsume", Parser::Unconsume); SetProtoMethod(isolate, t, "getCurrentBuffer", Parser::GetCurrentBuffer); - SetProtoMethod(isolate, t, "duration", Parser::Duration); - SetProtoMethod(isolate, t, "headersCompleted", Parser::HeadersCompleted); SetConstructorFunction(isolate, target, "HTTPParser", t); @@ -1381,8 +1367,6 @@ void RegisterExternalReferences(ExternalReferenceRegistry* registry) { registry->Register(Parser::Consume); registry->Register(Parser::Unconsume); registry->Register(Parser::GetCurrentBuffer); - registry->Register(Parser::Duration); - registry->Register(Parser::HeadersCompleted); registry->Register(ConnectionsList::New); registry->Register(ConnectionsList::All); registry->Register(ConnectionsList::Idle); diff --git a/src/node_i18n.cc b/src/node_i18n.cc index ea7810e41e2667..61b6ecd240c950 100644 --- a/src/node_i18n.cc +++ b/src/node_i18n.cc @@ -173,7 +173,7 @@ MaybeLocal TranscodeLatin1ToUcs2(Environment* env, const char* source, const size_t source_length, UErrorCode* status) { - MaybeStackBuffer destbuf(source_length); + MaybeStackBuffer destbuf(source_length); auto actual_length = simdutf::convert_latin1_to_utf16le(source, source_length, destbuf.out()); if (actual_length == 0) { @@ -217,7 +217,7 @@ MaybeLocal TranscodeUcs2FromUtf8(Environment* env, UErrorCode* status) { size_t expected_utf16_length = simdutf::utf16_length_from_utf8(source, source_length); - MaybeStackBuffer destbuf(expected_utf16_length); + MaybeStackBuffer destbuf(expected_utf16_length); auto actual_length = simdutf::convert_utf8_to_utf16le(source, source_length, destbuf.out()); diff --git a/src/node_messaging.cc b/src/node_messaging.cc index 6b3fb5d7da515b..42d0e32a9ec21b 100644 --- a/src/node_messaging.cc +++ b/src/node_messaging.cc @@ -1139,13 +1139,6 @@ void MessagePort::Stop(const FunctionCallbackInfo& args) { port->Stop(); } -void MessagePort::CheckType(const FunctionCallbackInfo& args) { - Environment* env = Environment::GetCurrent(args); - args.GetReturnValue().Set( - GetMessagePortConstructorTemplate(env->isolate_data()) - ->HasInstance(args[0])); -} - void MessagePort::Drain(const FunctionCallbackInfo& args) { MessagePort* port; ASSIGN_OR_RETURN_UNWRAP(&port, args[0].As()); @@ -1731,7 +1724,6 @@ static void CreatePerIsolateProperties(IsolateData* isolate_data, // These are not methods on the MessagePort prototype, because // the browser equivalents do not provide them. SetMethod(isolate, target, "stopMessagePort", MessagePort::Stop); - SetMethod(isolate, target, "checkMessagePort", MessagePort::CheckType); SetMethod(isolate, target, "drainMessagePort", MessagePort::Drain); SetMethod( isolate, target, "receiveMessageOnPort", MessagePort::ReceiveMessage); @@ -1767,7 +1759,6 @@ static void RegisterExternalReferences(ExternalReferenceRegistry* registry) { registry->Register(MessagePort::PostMessage); registry->Register(MessagePort::Start); registry->Register(MessagePort::Stop); - registry->Register(MessagePort::CheckType); registry->Register(MessagePort::Drain); registry->Register(MessagePort::ReceiveMessage); registry->Register(MessagePort::MoveToContext); diff --git a/src/node_messaging.h b/src/node_messaging.h index 169ff0ba19e909..3a838a39200a79 100644 --- a/src/node_messaging.h +++ b/src/node_messaging.h @@ -261,7 +261,6 @@ class MessagePort : public HandleWrap { static void PostMessage(const v8::FunctionCallbackInfo& args); static void Start(const v8::FunctionCallbackInfo& args); static void Stop(const v8::FunctionCallbackInfo& args); - static void CheckType(const v8::FunctionCallbackInfo& args); static void Drain(const v8::FunctionCallbackInfo& args); static void ReceiveMessage(const v8::FunctionCallbackInfo& args); diff --git a/src/node_metadata.cc b/src/node_metadata.cc index eea6686321a7bd..64b378969d2c35 100644 --- a/src/node_metadata.cc +++ b/src/node_metadata.cc @@ -11,7 +11,9 @@ #include "node.h" #include "simdjson.h" #include "simdutf.h" +#if HAVE_SQLITE #include "sqlite3.h" +#endif // HAVE_SQLITE #include "undici_version.h" #include "util.h" #include "uv.h" @@ -152,7 +154,9 @@ Metadata::Versions::Versions() { simdjson = SIMDJSON_VERSION; simdutf = SIMDUTF_VERSION; +#if HAVE_SQLITE sqlite = SQLITE_VERSION; +#endif // HAVE_SQLITE ada = ADA_VERSION; nbytes = NBYTES_VERSION; } diff --git a/src/node_metadata.h b/src/node_metadata.h index 6f8cb433ff8059..7b2072ad39c3f1 100644 --- a/src/node_metadata.h +++ b/src/node_metadata.h @@ -55,7 +55,6 @@ namespace node { V(acorn) \ V(simdjson) \ V(simdutf) \ - V(sqlite) \ V(ada) \ V(nbytes) \ NODE_VERSIONS_KEY_AMARO(V) \ @@ -86,11 +85,18 @@ namespace node { #define NODE_VERSIONS_KEY_QUIC(V) #endif +#if HAVE_SQLITE +#define NODE_VERSIONS_KEY_SQLITE(V) V(sqlite) +#else +#define NODE_VERSIONS_KEY_SQLITE(V) +#endif + #define NODE_VERSIONS_KEYS(V) \ NODE_VERSIONS_KEYS_BASE(V) \ NODE_VERSIONS_KEY_CRYPTO(V) \ NODE_VERSIONS_KEY_INTL(V) \ - NODE_VERSIONS_KEY_QUIC(V) + NODE_VERSIONS_KEY_QUIC(V) \ + NODE_VERSIONS_KEY_SQLITE(V) class Metadata { public: diff --git a/src/node_options.cc b/src/node_options.cc index 3fc8194475ec0e..da39abf79c53fc 100644 --- a/src/node_options.cc +++ b/src/node_options.cc @@ -647,6 +647,9 @@ EnvironmentOptionsParser::EnvironmentOptionsParser() { AddOption("--experimental-network-inspection", "experimental network inspection support", &EnvironmentOptions::experimental_network_inspection); + AddOption("--experimental-worker-inspection", + "experimental worker inspection support", + &EnvironmentOptions::experimental_worker_inspection); AddOption( "--heap-prof", "Start the V8 heap profiler on start up, and write the heap profile " diff --git a/src/node_options.h b/src/node_options.h index 7d14f06370d936..165950c207ca75 100644 --- a/src/node_options.h +++ b/src/node_options.h @@ -171,6 +171,7 @@ class EnvironmentOptions : public Options { std::string cpu_prof_name; bool cpu_prof = false; bool experimental_network_inspection = false; + bool experimental_worker_inspection = false; std::string heap_prof_dir; std::string heap_prof_name; static const uint64_t kDefaultHeapProfInterval = 512 * 1024; diff --git a/src/node_os.cc b/src/node_os.cc index 8da7e7f9eb78c8..ff9e1975b2afdb 100644 --- a/src/node_os.cc +++ b/src/node_os.cc @@ -20,6 +20,7 @@ // USE OR OTHER DEALINGS IN THE SOFTWARE. #include "env-inl.h" +#include "node_debug.h" #include "node_external_reference.h" #include "string_bytes.h" @@ -148,12 +149,26 @@ static void GetFreeMemory(const FunctionCallbackInfo& args) { args.GetReturnValue().Set(amount); } +static double FastGetFreeMemory(Local receiver) { + TRACK_V8_FAST_API_CALL("os.freemem"); + return static_cast(uv_get_free_memory()); +} + +static v8::CFunction fast_get_free_memory( + v8::CFunction::Make(FastGetFreeMemory)); static void GetTotalMemory(const FunctionCallbackInfo& args) { double amount = static_cast(uv_get_total_memory()); args.GetReturnValue().Set(amount); } +double FastGetTotalMemory(Local receiver) { + TRACK_V8_FAST_API_CALL("os.totalmem"); + return static_cast(uv_get_total_memory()); +} + +static v8::CFunction fast_get_total_memory( + v8::CFunction::Make(FastGetTotalMemory)); static void GetUptime(const FunctionCallbackInfo& args) { Environment* env = Environment::GetCurrent(args); @@ -406,6 +421,14 @@ static void GetAvailableParallelism(const FunctionCallbackInfo& args) { args.GetReturnValue().Set(parallelism); } +uint32_t FastGetAvailableParallelism(v8::Local receiver) { + TRACK_V8_FAST_API_CALL("os.availableParallelism"); + return uv_available_parallelism(); +} + +static v8::CFunction fast_get_available_parallelism( + v8::CFunction::Make(FastGetAvailableParallelism)); + void Initialize(Local target, Local unused, Local context, @@ -414,16 +437,21 @@ void Initialize(Local target, SetMethod(context, target, "getHostname", GetHostname); SetMethod(context, target, "getLoadAvg", GetLoadAvg); SetMethod(context, target, "getUptime", GetUptime); - SetMethod(context, target, "getTotalMem", GetTotalMemory); - SetMethod(context, target, "getFreeMem", GetFreeMemory); + SetFastMethodNoSideEffect( + context, target, "getTotalMem", GetTotalMemory, &fast_get_total_memory); + SetFastMethodNoSideEffect( + context, target, "getFreeMem", GetFreeMemory, &fast_get_free_memory); SetMethod(context, target, "getCPUs", GetCPUInfo); SetMethod(context, target, "getInterfaceAddresses", GetInterfaceAddresses); SetMethod(context, target, "getHomeDirectory", GetHomeDirectory); SetMethod(context, target, "getUserInfo", GetUserInfo); SetMethod(context, target, "setPriority", SetPriority); SetMethod(context, target, "getPriority", GetPriority); - SetMethod( - context, target, "getAvailableParallelism", GetAvailableParallelism); + SetFastMethodNoSideEffect(context, + target, + "getAvailableParallelism", + GetAvailableParallelism, + &fast_get_available_parallelism); SetMethod(context, target, "getOSInformation", GetOSInformation); target ->Set(context, @@ -437,7 +465,11 @@ void RegisterExternalReferences(ExternalReferenceRegistry* registry) { registry->Register(GetLoadAvg); registry->Register(GetUptime); registry->Register(GetTotalMemory); + registry->Register(FastGetTotalMemory); + registry->Register(fast_get_total_memory.GetTypeInfo()); registry->Register(GetFreeMemory); + registry->Register(FastGetFreeMemory); + registry->Register(fast_get_free_memory.GetTypeInfo()); registry->Register(GetCPUInfo); registry->Register(GetInterfaceAddresses); registry->Register(GetHomeDirectory); @@ -445,6 +477,8 @@ void RegisterExternalReferences(ExternalReferenceRegistry* registry) { registry->Register(SetPriority); registry->Register(GetPriority); registry->Register(GetAvailableParallelism); + registry->Register(FastGetAvailableParallelism); + registry->Register(fast_get_available_parallelism.GetTypeInfo()); registry->Register(GetOSInformation); } diff --git a/src/node_report.cc b/src/node_report.cc index 9ab66162ec32a6..da7b846d555ba6 100644 --- a/src/node_report.cc +++ b/src/node_report.cc @@ -676,9 +676,9 @@ static void PrintResourceUsage(JSONWriter* writer) { writer->json_objectend(); } writer->json_objectend(); -#ifdef RUSAGE_THREAD - struct rusage stats; - if (getrusage(RUSAGE_THREAD, &stats) == 0) { + + uv_rusage_t stats; + if (uv_getrusage_thread(&stats) == 0) { writer->json_objectstart("uvthreadResourceUsage"); double user_cpu = stats.ru_utime.tv_sec + SEC_PER_MICROS * stats.ru_utime.tv_usec; @@ -699,7 +699,6 @@ static void PrintResourceUsage(JSONWriter* writer) { writer->json_objectend(); writer->json_objectend(); } -#endif // RUSAGE_THREAD } static void PrintEnvironmentVariables(JSONWriter* writer) { diff --git a/src/node_sea.cc b/src/node_sea.cc index 1f7f3c8a707f4e..65a338e00d4e22 100644 --- a/src/node_sea.cc +++ b/src/node_sea.cc @@ -41,6 +41,7 @@ using v8::MaybeLocal; using v8::NewStringType; using v8::Object; using v8::ScriptCompiler; +using v8::ScriptOrigin; using v8::String; using v8::Value; @@ -460,16 +461,23 @@ std::optional GenerateCodeCache(std::string_view main_path, FIXED_ONE_BYTE_STRING(isolate, "__filename"), FIXED_ONE_BYTE_STRING(isolate, "__dirname"), }); - - // TODO(RaisinTen): Using the V8 code cache prevents us from using `import()` - // in the SEA code. Support it. - // Refs: https://github.com/nodejs/node/pull/48191#discussion_r1213271430 + ScriptOrigin script_origin(filename, 0, 0, true); + ScriptCompiler::Source script_source(content, script_origin); + MaybeLocal maybe_fn = + ScriptCompiler::CompileFunction(context, + &script_source, + parameters.size(), + parameters.data(), + 0, + nullptr); Local fn; - if (!contextify::CompileFunction(context, filename, content, ¶meters) - .ToLocal(&fn)) { + if (!maybe_fn.ToLocal(&fn)) { return std::nullopt; } + // TODO(RaisinTen): Using the V8 code cache prevents us from using `import()` + // in the SEA code. Support it. + // Refs: https://github.com/nodejs/node/pull/48191#discussion_r1213271430 std::unique_ptr cache{ ScriptCompiler::CreateCodeCacheForFunction(fn)}; std::string code_cache(cache->data, cache->data + cache->length); diff --git a/src/node_snapshotable.cc b/src/node_snapshotable.cc index 7207e68d127ae0..a500204c4768e2 100644 --- a/src/node_snapshotable.cc +++ b/src/node_snapshotable.cc @@ -42,8 +42,11 @@ using v8::HandleScope; using v8::Isolate; using v8::Local; using v8::LocalVector; +using v8::MaybeLocal; using v8::Object; using v8::ObjectTemplate; +using v8::ScriptCompiler; +using v8::ScriptOrigin; using v8::SnapshotCreator; using v8::StartupData; using v8::String; @@ -1487,9 +1490,18 @@ void CompileSerializeMain(const FunctionCallbackInfo& args) { FIXED_ONE_BYTE_STRING(isolate, "__filename"), FIXED_ONE_BYTE_STRING(isolate, "__dirname"), }); + + ScriptOrigin script_origin(filename, 0, 0, true); + ScriptCompiler::Source script_source(source, script_origin); + MaybeLocal maybe_fn = + ScriptCompiler::CompileFunction(context, + &script_source, + parameters.size(), + parameters.data(), + 0, + nullptr); Local fn; - if (contextify::CompileFunction(context, filename, source, ¶meters) - .ToLocal(&fn)) { + if (maybe_fn.ToLocal(&fn)) { args.GetReturnValue().Set(fn); } } diff --git a/src/node_sqlite.cc b/src/node_sqlite.cc index 77d506142eedf5..a5ef24033b9207 100644 --- a/src/node_sqlite.cc +++ b/src/node_sqlite.cc @@ -373,7 +373,10 @@ class CustomAggregate { result = Local::New(isolate, agg->value); } - JSValueToSQLiteResult(isolate, ctx, result); + if (!result.IsEmpty()) { + JSValueToSQLiteResult(isolate, ctx, result); + } + if (is_final) { DestroyAggregateData(ctx); } @@ -2687,9 +2690,11 @@ static void Initialize(Local target, Local backup_function; - if (!Function::New(context, Backup).ToLocal(&backup_function)) { + if (!Function::New(context, Backup, Local(), 2) + .ToLocal(&backup_function)) { return; } + backup_function->SetName(env->backup_string()); target->Set(context, env->backup_string(), backup_function).Check(); } diff --git a/src/node_v8.cc b/src/node_v8.cc index a8d4cf42edf762..4b967dcd52f361 100644 --- a/src/node_v8.cc +++ b/src/node_v8.cc @@ -385,23 +385,13 @@ static MaybeLocal ConvertHeapStatsToJSObject( FIXED_ONE_BYTE_STRING(isolate, "bucket_size"), FIXED_ONE_BYTE_STRING(isolate, "free_count"), FIXED_ONE_BYTE_STRING(isolate, "free_size")}; - Local bucket_size_value; - if (!ToV8Value(context, space_stats.free_list_stats.bucket_size) - .ToLocal(&bucket_size_value)) { - return MaybeLocal(); - } - Local free_count_value; - if (!ToV8Value(context, space_stats.free_list_stats.free_count) - .ToLocal(&free_count_value)) { - return MaybeLocal(); - } - Local free_size_value; - if (!ToV8Value(context, space_stats.free_list_stats.free_size) - .ToLocal(&free_size_value)) { - return MaybeLocal(); - } Local free_list_statistics_values[] = { - bucket_size_value, free_count_value, free_size_value}; + ToV8ValuePrimitiveArray( + context, space_stats.free_list_stats.bucket_size, isolate), + ToV8ValuePrimitiveArray( + context, space_stats.free_list_stats.free_count, isolate), + ToV8ValuePrimitiveArray( + context, space_stats.free_list_stats.free_size, isolate)}; Local free_list_statistics_obj = Object::New(isolate, diff --git a/src/node_version.h b/src/node_version.h index 6a25754aae327c..e201313e65678e 100644 --- a/src/node_version.h +++ b/src/node_version.h @@ -23,13 +23,13 @@ #define SRC_NODE_VERSION_H_ #define NODE_MAJOR_VERSION 22 -#define NODE_MINOR_VERSION 16 -#define NODE_PATCH_VERSION 1 +#define NODE_MINOR_VERSION 17 +#define NODE_PATCH_VERSION 0 #define NODE_VERSION_IS_LTS 1 #define NODE_VERSION_LTS_CODENAME "Jod" -#define NODE_VERSION_IS_RELEASE 0 +#define NODE_VERSION_IS_RELEASE 1 #ifndef NODE_STRINGIFY #define NODE_STRINGIFY(n) NODE_STRINGIFY_HELPER(n) diff --git a/src/permission/fs_permission.cc b/src/permission/fs_permission.cc index 6d11e06e46ebe8..0d42b3f535a597 100644 --- a/src/permission/fs_permission.cc +++ b/src/permission/fs_permission.cc @@ -45,9 +45,7 @@ void FreeRecursivelyNode( } } - if (node->wildcard_child != nullptr) { - delete node->wildcard_child; - } + delete node->wildcard_child; delete node; } diff --git a/src/quic/sessionticket.h b/src/quic/sessionticket.h index a2e6e3758f6f9c..bdfd38be72d22a 100644 --- a/src/quic/sessionticket.h +++ b/src/quic/sessionticket.h @@ -58,7 +58,7 @@ class SessionTicket final : public MemoryRetainer { }; // SessionTicket::AppData is a utility class that is used only during the -// generation or access of TLS stateless sesson tickets. It exists solely to +// generation or access of TLS stateless session tickets. It exists solely to // provide a easier way for Session::Application instances to set relevant // metadata in the session ticket when it is created, and the extract and // subsequently verify that data when a ticket is received and is being diff --git a/src/quic/streams.h b/src/quic/streams.h index 0bacb37faf542d..8a9721ebe2a9ee 100644 --- a/src/quic/streams.h +++ b/src/quic/streams.h @@ -203,7 +203,7 @@ class Stream : public AsyncWrap, std::unique_ptr outbound_; std::shared_ptr inbound_; - std::vector> headers_; + v8::LocalVector headers_; HeadersKind headers_kind_ = HeadersKind::INITIAL; size_t headers_length_ = 0; diff --git a/src/tty_wrap.cc b/src/tty_wrap.cc index 4907d8394c7f47..37c58cf0cb7adc 100644 --- a/src/tty_wrap.cc +++ b/src/tty_wrap.cc @@ -116,7 +116,17 @@ void TTYWrap::SetRawMode(const FunctionCallbackInfo& args) { TTYWrap* wrap; ASSIGN_OR_RETURN_UNWRAP( &wrap, args.This(), args.GetReturnValue().Set(UV_EBADF)); - int err = uv_tty_set_mode(&wrap->handle_, args[0]->IsTrue()); + // UV_TTY_MODE_RAW_VT is a variant of UV_TTY_MODE_RAW that + // enables control sequence processing on the TTY implementer side, + // rather than having libuv translate keypress events into + // control sequences, aligning behavior more closely with + // POSIX platforms. This is also required to support some control + // sequences at all on Windows, such as bracketed paste mode. + // The Node.js readline implementation handles differences between + // these modes. + int err = uv_tty_set_mode( + &wrap->handle_, + args[0]->IsTrue() ? UV_TTY_MODE_RAW_VT : UV_TTY_MODE_NORMAL); args.GetReturnValue().Set(err); } diff --git a/src/util-inl.h b/src/util-inl.h index f92c8297dcb8e7..a9420d20ca070d 100644 --- a/src/util-inl.h +++ b/src/util-inl.h @@ -428,12 +428,9 @@ v8::MaybeLocal ToV8Value(v8::Local context, return handle_scope.Escape(ret); } -template -v8::MaybeLocal ToV8Value(v8::Local context, - const T& number, - v8::Isolate* isolate) { - if (isolate == nullptr) isolate = context->GetIsolate(); - +template +v8::Local ConvertNumberToV8Value(v8::Isolate* isolate, + const T& number) { using Limits = std::numeric_limits; // Choose Uint32, Int32, or Double depending on range checks. // These checks should all collapse at compile time. @@ -454,6 +451,43 @@ v8::MaybeLocal ToV8Value(v8::Local context, return v8::Number::New(isolate, static_cast(number)); } +template +v8::MaybeLocal ToV8Value(v8::Local context, + const T& number, + v8::Isolate* isolate) { + if (isolate == nullptr) isolate = context->GetIsolate(); + return ConvertNumberToV8Value(isolate, number); +} + +template +v8::Local ToV8ValuePrimitiveArray(v8::Local context, + const std::vector& vec, + v8::Isolate* isolate) { + static_assert( + std::is_same_v || std::is_integral_v || + std::is_floating_point_v, + "Only primitive types (bool, integral, floating-point) are supported."); + + if (isolate == nullptr) isolate = context->GetIsolate(); + v8::EscapableHandleScope handle_scope(isolate); + + v8::LocalVector elements(isolate); + elements.reserve(vec.size()); + + for (const auto& value : vec) { + if constexpr (std::is_same_v) { + elements.emplace_back(v8::Boolean::New(isolate, value)); + } else { + v8::Local v = ConvertNumberToV8Value(isolate, value); + elements.emplace_back(v); + } + } + + v8::Local arr = + v8::Array::New(isolate, elements.data(), elements.size()); + return handle_scope.Escape(arr); +} + SlicedArguments::SlicedArguments( const v8::FunctionCallbackInfo& args, size_t start) { const size_t length = static_cast(args.Length()); diff --git a/src/util.h b/src/util.h index a77332f583402a..6376cf4f81113c 100644 --- a/src/util.h +++ b/src/util.h @@ -655,38 +655,6 @@ struct MallocedBuffer { MallocedBuffer& operator=(const MallocedBuffer&) = delete; }; -template -class NonCopyableMaybe { - public: - NonCopyableMaybe() : empty_(true) {} - explicit NonCopyableMaybe(T&& value) - : empty_(false), - value_(std::move(value)) {} - - bool IsEmpty() const { - return empty_; - } - - const T* get() const { - return empty_ ? nullptr : &value_; - } - - const T* operator->() const { - CHECK(!empty_); - return &value_; - } - - T&& Release() { - CHECK_EQ(empty_, false); - empty_ = true; - return std::move(value_); - } - - private: - bool empty_; - T value_; -}; - // Test whether some value can be called with (). template struct is_callable : std::is_function { }; diff --git a/test/addons/make-callback/binding.cc b/test/addons/make-callback/binding.cc index 86ed203b98d8d9..920ec3df43cd19 100644 --- a/test/addons/make-callback/binding.cc +++ b/test/addons/make-callback/binding.cc @@ -11,7 +11,7 @@ void MakeCallback(const v8::FunctionCallbackInfo& args) { assert(args[1]->IsFunction() || args[1]->IsString()); auto isolate = args.GetIsolate(); auto recv = args[0].As(); - std::vector> argv; + v8::LocalVector argv(isolate); for (size_t n = 2; n < static_cast(args.Length()); n += 1) { argv.push_back(args[n]); } diff --git a/test/addons/openssl-providers/binding.cc b/test/addons/openssl-providers/binding.cc index 76cd076c1d953c..785a103bb6c6c7 100644 --- a/test/addons/openssl-providers/binding.cc +++ b/test/addons/openssl-providers/binding.cc @@ -13,6 +13,7 @@ using v8::Context; using v8::FunctionCallbackInfo; using v8::Isolate; using v8::Local; +using v8::LocalVector; using v8::Object; using v8::String; using v8::Value; @@ -26,7 +27,7 @@ int collectProviders(OSSL_PROVIDER* provider, void* cbdata) { inline void GetProviders(const FunctionCallbackInfo& args) { Isolate* isolate = args.GetIsolate(); - std::vector> arr = {}; + LocalVector arr(isolate, 0); #if OPENSSL_VERSION_MAJOR >= 3 std::vector providers; OSSL_PROVIDER_do_all(nullptr, &collectProviders, &providers); diff --git a/test/async-hooks/test-async-local-storage-gcable.js b/test/async-hooks/test-async-local-storage-gcable.js index ef3f15677463f8..280bcedd5e501f 100644 --- a/test/async-hooks/test-async-local-storage-gcable.js +++ b/test/async-hooks/test-async-local-storage-gcable.js @@ -1,11 +1,12 @@ 'use strict'; -// Flags: --expose_gc +// Flags: --expose_gc --expose-internals // This test ensures that AsyncLocalStorage gets gced once it was disabled // and no strong references remain in userland. const common = require('../common'); const { AsyncLocalStorage } = require('async_hooks'); +const AsyncContextFrame = require('internal/async_context_frame'); const { onGC } = require('../common/gc'); let asyncLocalStorage = new AsyncLocalStorage(); @@ -16,5 +17,11 @@ asyncLocalStorage.run({}, () => { onGC(asyncLocalStorage, { ongc: common.mustCall() }); }); +if (AsyncContextFrame.enabled) { + // This disable() is needed to remove reference form AsyncContextFrame + // created during exit of run() to the AsyncLocalStore instance. + asyncLocalStorage.disable(); +} + asyncLocalStorage = null; global.gc(); diff --git a/test/async-hooks/test-emit-after-on-destroyed.js b/test/async-hooks/test-emit-after-on-destroyed.js index 1a10a1dfc74a74..913cec7bd6a61b 100644 --- a/test/async-hooks/test-emit-after-on-destroyed.js +++ b/test/async-hooks/test-emit-after-on-destroyed.js @@ -52,8 +52,15 @@ if (process.argv[2] === 'child') { child.stderr.on('data', (d) => { errData = Buffer.concat([ errData, d ]); }); child.stdout.on('data', (d) => { outData = Buffer.concat([ outData, d ]); }); - child.on('close', common.mustCall((code) => { - assert.strictEqual(code, 1); + child.on('close', common.mustCall((code, signal) => { + if ((common.isAIX || + (common.isLinux && process.arch === 'x64')) && + signal === 'SIGABRT') { + // XXX: The child process could be aborted due to unknown reasons. Work around it. + } else { + assert.strictEqual(signal, null); + assert.strictEqual(code, 1); + } assert.match(outData.toString(), heartbeatMsg, 'did not crash until we reached offending line of code ' + `(found ${outData})`); diff --git a/test/async-hooks/test-improper-unwind.js b/test/async-hooks/test-improper-unwind.js index ea0eee025d7fd3..fb7f212a6804b2 100644 --- a/test/async-hooks/test-improper-unwind.js +++ b/test/async-hooks/test-improper-unwind.js @@ -55,8 +55,15 @@ if (process.argv[2] === 'child') { child.stderr.on('data', (d) => { errData = Buffer.concat([ errData, d ]); }); child.stdout.on('data', (d) => { outData = Buffer.concat([ outData, d ]); }); - child.on('close', common.mustCall((code) => { - assert.strictEqual(code, 1); + child.on('close', common.mustCall((code, signal) => { + if ((common.isAIX || + (common.isLinux && process.arch === 'x64')) && + signal === 'SIGABRT') { + // XXX: The child process could be aborted due to unknown reasons. Work around it. + } else { + assert.strictEqual(signal, null); + assert.strictEqual(code, 1); + } assert.match(outData.toString(), heartbeatMsg, 'did not crash until we reached offending line of code ' + `(found ${outData})`); diff --git a/test/cctest/node_test_fixture.cc b/test/cctest/node_test_fixture.cc index cae9c7b76aee88..6b75e88d14c2b0 100644 --- a/test/cctest/node_test_fixture.cc +++ b/test/cctest/node_test_fixture.cc @@ -21,9 +21,6 @@ void NodeTestEnvironment::SetUp() { NodeZeroIsolateTestFixture::platform.reset( new node::NodePlatform(kV8ThreadPoolSize, tracing_controller)); v8::V8::InitializePlatform(NodeZeroIsolateTestFixture::platform.get()); -#ifdef V8_ENABLE_SANDBOX - ASSERT_TRUE(v8::V8::InitializeSandbox()); -#endif cppgc::InitializeProcess( NodeZeroIsolateTestFixture::platform->GetPageAllocator()); diff --git a/test/common/README.md b/test/common/README.md index 720ff33fd60f36..a5b90abf1f006f 100644 --- a/test/common/README.md +++ b/test/common/README.md @@ -257,6 +257,12 @@ Indicates if [internationalization][] is supported. Indicates whether `IPv6` is supported on this platform. +### `hasSQLite` + +* [\][] + +Indicates whether SQLite is available. + ### `inFreeBSDJail` * [\][] @@ -481,6 +487,11 @@ at `tools/eslint/node_modules/eslint` Skip the rest of the tests in the current file when the Inspector was disabled at compile time. +### `skipIfSQLiteMissing()` + +Skip the rest of the tests in the current file when the SQLite +was disabled at compile time. + ### `skipIf32Bits()` Skip the rest of the tests in the current file when the Node.js executable diff --git a/test/common/assertSnapshot.js b/test/common/assertSnapshot.js index dbd4a6079861fc..7a40c94389eda9 100644 --- a/test/common/assertSnapshot.js +++ b/test/common/assertSnapshot.js @@ -16,6 +16,10 @@ function replaceStackTrace(str, replacement = '$1*$7$8\n') { return str.replace(stackFramesRegexp, replacement); } +function replaceInternalStackTrace(str) { + return str.replaceAll(/(\W+).*node:internal.*/g, '$1*'); +} + function replaceWindowsLineEndings(str) { return str.replace(windowNewlineRegexp, ''); } @@ -24,8 +28,11 @@ function replaceWindowsPaths(str) { return common.isWindows ? str.replaceAll(path.win32.sep, path.posix.sep) : str; } -function replaceFullPaths(str) { - return str.replaceAll('\\\'', "'").replaceAll(path.resolve(__dirname, '../..'), ''); +function transformProjectRoot(replacement = '') { + const projectRoot = path.resolve(__dirname, '../..'); + return (str) => { + return str.replaceAll('\\\'', "'").replaceAll(projectRoot, replacement); + }; } function transform(...args) { @@ -94,11 +101,12 @@ async function spawnAndAssert(filename, transform = (x) => x, { tty = false, ... module.exports = { assertSnapshot, getSnapshotPath, - replaceFullPaths, replaceNodeVersion, replaceStackTrace, + replaceInternalStackTrace, replaceWindowsLineEndings, replaceWindowsPaths, spawnAndAssert, transform, + transformProjectRoot, }; diff --git a/test/common/index.js b/test/common/index.js old mode 100644 new mode 100755 index 8f5af57a83dc6b..1cd23e9354229f --- a/test/common/index.js +++ b/test/common/index.js @@ -54,6 +54,8 @@ const noop = () => {}; const hasCrypto = Boolean(process.versions.openssl) && !process.env.NODE_SKIP_CRYPTO; +const hasSQLite = Boolean(process.versions.sqlite); + const hasQuic = hasCrypto && !!process.config.variables.openssl_quic; function parseTestFlags(filename = process.argv[1]) { @@ -682,6 +684,12 @@ function skipIf32Bits() { } } +function skipIfSQLiteMissing() { + if (!hasSQLite) { + skip('missing SQLite'); + } +} + function getArrayBufferViews(buf) { const { buffer, byteOffset, byteLength } = buf; @@ -883,6 +891,7 @@ const common = { hasIntl, hasCrypto, hasQuic, + hasSQLite, invalidArgTypeHelper, isAlive, isASan, @@ -912,6 +921,7 @@ const common = { skipIf32Bits, skipIfEslintMissing, skipIfInspectorDisabled, + skipIfSQLiteMissing, spawnPromisified, get enoughTestMem() { diff --git a/test/common/index.mjs b/test/common/index.mjs index dd0adadcb28d38..51f4bb222b6b81 100644 --- a/test/common/index.mjs +++ b/test/common/index.mjs @@ -16,6 +16,7 @@ const { getBufferSources, getTTYfd, hasCrypto, + hasSQLite, hasIntl, hasIPv6, isAIX, @@ -44,6 +45,7 @@ const { skipIf32Bits, skipIfEslintMissing, skipIfInspectorDisabled, + skipIfSQLiteMissing, spawnPromisified, } = common; @@ -64,6 +66,7 @@ export { getPort, getTTYfd, hasCrypto, + hasSQLite, hasIntl, hasIPv6, isAIX, @@ -92,5 +95,6 @@ export { skipIf32Bits, skipIfEslintMissing, skipIfInspectorDisabled, + skipIfSQLiteMissing, spawnPromisified, }; diff --git a/test/common/tmpdir.js b/test/common/tmpdir.js index 4ff45b7635e3b1..d56a733110590d 100644 --- a/test/common/tmpdir.js +++ b/test/common/tmpdir.js @@ -39,7 +39,7 @@ const testRoot = process.env.NODE_TEST_DIR ? // gets tools to ignore it by default or by simple rules, especially eslint. const tmpdirName = '.tmp.' + (process.env.TEST_SERIAL_ID || process.env.TEST_THREAD_ID || '0'); -const tmpPath = path.join(testRoot, tmpdirName); +let tmpPath = path.join(testRoot, tmpdirName); let firstRefresh = true; function refresh(useSpawn = false) { @@ -100,7 +100,13 @@ function fileURL(...paths) { module.exports = { fileURL, hasEnoughSpace, - path: tmpPath, refresh, resolve, + + get path() { + return tmpPath; + }, + set path(newPath) { + tmpPath = path.resolve(newPath); + }, }; diff --git a/test/es-module/es-module.status b/test/es-module/es-module.status index 58a422dc152258..32b712cbef0c8f 100644 --- a/test/es-module/es-module.status +++ b/test/es-module/es-module.status @@ -13,3 +13,7 @@ test-esm-loader-http-imports: PASS,FLAKY [$arch==arm || $arch==arm64] # https://github.com/nodejs/node/issues/47297 test-wasm-web-api: SKIP + +[$system==ibmi] +# https://github.com/nodejs/node/issues/58582 +test-wasm-web-api: PASS,FLAKY diff --git a/test/es-module/test-require-module-error-catching.js b/test/es-module/test-require-module-error-catching.js index c314513d9bbf04..5400564b3182c6 100644 --- a/test/es-module/test-require-module-error-catching.js +++ b/test/es-module/test-require-module-error-catching.js @@ -17,5 +17,5 @@ assert.throws(() => { require('../fixtures/es-modules/reference-error-esm.js'); }, { name: 'ReferenceError', - message: 'exports is not defined' + message: 'exports is not defined in ES module scope' }); diff --git a/test/es-module/test-require-module-instantiated.mjs b/test/es-module/test-require-module-instantiated.mjs new file mode 100644 index 00000000000000..9dd50f31d36fd4 --- /dev/null +++ b/test/es-module/test-require-module-instantiated.mjs @@ -0,0 +1,4 @@ +import '../common/index.mjs'; +import assert from 'node:assert'; +import { b, c } from '../fixtures/es-modules/require-module-instantiated/a.mjs'; +assert.strictEqual(b, c); diff --git a/test/es-module/test-wasm-web-api.js b/test/es-module/test-wasm-web-api.js index b199393a18c370..879748e4403b07 100644 --- a/test/es-module/test-wasm-web-api.js +++ b/test/es-module/test-wasm-web-api.js @@ -106,7 +106,9 @@ function testCompileStreamingRejectionUsingFetch(responseCallback, rejection) { // Response whose body is a ReadableStream instead of calling fetch(). await testCompileStreamingSuccess(async () => { const handle = await fs.open(fixtures.path('simple.wasm')); - const stream = handle.readableWebStream(); + // We set the autoClose option to true so that the file handle is closed + // automatically when the stream is completed or canceled. + const stream = handle.readableWebStream({ autoClose: true }); return Promise.resolve(new Response(stream, { status: 200, headers: { 'Content-Type': 'application/wasm' } diff --git a/test/fixtures/console/stack_overflow.js b/test/fixtures/console/stack_overflow.js index 565692b6d6e4ba..14bceef878b5cf 100644 --- a/test/fixtures/console/stack_overflow.js +++ b/test/fixtures/console/stack_overflow.js @@ -26,11 +26,15 @@ Error.stackTraceLimit = 0; console.error('before'); +// Invalidate elements protector to force slow-path. +// The fast-path of JSON.stringify is iterative and won't throw. +Array.prototype[2] = 'foo'; + // Trigger stack overflow by stringifying a deeply nested array. -let array = []; -for (let i = 0; i < 100000; i++) { - array = [ array ]; -} +// eslint-disable-next-line no-sparse-arrays +let array = [,]; +for (let i = 0; i < 10000; i++) + array = [array]; JSON.stringify(array); diff --git a/test/fixtures/es-modules/require-module-instantiated/a.mjs b/test/fixtures/es-modules/require-module-instantiated/a.mjs new file mode 100644 index 00000000000000..2918d41462152f --- /dev/null +++ b/test/fixtures/es-modules/require-module-instantiated/a.mjs @@ -0,0 +1,2 @@ +export { default as b } from './b.cjs'; +export { default as c } from './c.mjs'; diff --git a/test/fixtures/es-modules/require-module-instantiated/b.cjs b/test/fixtures/es-modules/require-module-instantiated/b.cjs new file mode 100644 index 00000000000000..1e23a5d46d2ad2 --- /dev/null +++ b/test/fixtures/es-modules/require-module-instantiated/b.cjs @@ -0,0 +1 @@ +module.exports = require('./c.mjs'); diff --git a/test/fixtures/es-modules/require-module-instantiated/c.mjs b/test/fixtures/es-modules/require-module-instantiated/c.mjs new file mode 100644 index 00000000000000..a5b4faccf9a4fd --- /dev/null +++ b/test/fixtures/es-modules/require-module-instantiated/c.mjs @@ -0,0 +1,3 @@ +const foo = 1; +export default foo; +export { foo as 'module.exports' }; diff --git a/test/fixtures/inspect-worker/index.js b/test/fixtures/inspect-worker/index.js new file mode 100644 index 00000000000000..b0f883ef4b0453 --- /dev/null +++ b/test/fixtures/inspect-worker/index.js @@ -0,0 +1,3 @@ +const { Worker } = require('worker_threads'); + +new Worker(__dirname + '/worker.js', { type: 'module' }); diff --git a/test/fixtures/inspect-worker/worker.js b/test/fixtures/inspect-worker/worker.js new file mode 100644 index 00000000000000..9729bd7b41c6e1 --- /dev/null +++ b/test/fixtures/inspect-worker/worker.js @@ -0,0 +1,4 @@ +console.log("worker thread"); +process.on('exit', () => { + console.log('Worker1: Exiting...'); +}); diff --git a/test/fixtures/module-mocking/basic.json b/test/fixtures/module-mocking/basic.json new file mode 100644 index 00000000000000..2393cd01d4bfa0 --- /dev/null +++ b/test/fixtures/module-mocking/basic.json @@ -0,0 +1 @@ +{"foo":"bar"} diff --git a/test/fixtures/permission/fs-read-loader.js b/test/fixtures/permission/fs-read-loader.js new file mode 100644 index 00000000000000..aaef61e8ce715d --- /dev/null +++ b/test/fixtures/permission/fs-read-loader.js @@ -0,0 +1,15 @@ +const fs = require('node:fs') +const path = require('node:path') +const assert = require('node:assert'); + +{ + fs.readFileSync(__filename); + console.log('Read its own contents') // Should not throw +} +{ + const simpleLoaderPath = path.join(__dirname, 'simple-loader.js'); + fs.readFile(simpleLoaderPath, (err) => { + assert.ok(err.code, 'ERR_ACCESS_DENIED'); + assert.ok(err.permission, 'FileSystemRead'); + }); // Should throw ERR_ACCESS_DENIED +} \ No newline at end of file diff --git a/test/fixtures/permission/hello-world.js b/test/fixtures/permission/hello-world.js new file mode 100644 index 00000000000000..f5bda8dadd6a09 --- /dev/null +++ b/test/fixtures/permission/hello-world.js @@ -0,0 +1 @@ +console.log('Hello world') \ No newline at end of file diff --git a/test/fixtures/permission/simple-loader.js b/test/fixtures/permission/simple-loader.js new file mode 100644 index 00000000000000..43e2a9bb77899b --- /dev/null +++ b/test/fixtures/permission/simple-loader.js @@ -0,0 +1,3 @@ +// Simulate a regular loading without fs operations +// but with access to Node core modules +require('node:fs') \ No newline at end of file diff --git a/test/fixtures/rc/inspect-false.json b/test/fixtures/rc/inspect-false.json new file mode 100644 index 00000000000000..32bb5961f24d0d --- /dev/null +++ b/test/fixtures/rc/inspect-false.json @@ -0,0 +1,5 @@ +{ + "nodeOptions": { + "inspect": false + } +} diff --git a/test/fixtures/rc/inspect-true.json b/test/fixtures/rc/inspect-true.json new file mode 100644 index 00000000000000..684571a5a691a2 --- /dev/null +++ b/test/fixtures/rc/inspect-true.json @@ -0,0 +1,5 @@ +{ + "nodeOptions": { + "inspect": true + } +} diff --git a/test/fixtures/rc/non-readable/node.config.json b/test/fixtures/rc/non-readable/node.config.json old mode 100755 new mode 100644 diff --git a/test/fixtures/source-map/output/source_map_disabled_by_api.snapshot b/test/fixtures/source-map/output/source_map_disabled_by_api.snapshot index 655cd6695e1116..f538904873393e 100644 --- a/test/fixtures/source-map/output/source_map_disabled_by_api.snapshot +++ b/test/fixtures/source-map/output/source_map_disabled_by_api.snapshot @@ -1,12 +1,12 @@ Error: an error! - at functionD (*enclosing-call-site-min.js:1:156) - at functionC (*enclosing-call-site-min.js:1:97) - at functionB (*enclosing-call-site-min.js:1:60) - at functionA (*enclosing-call-site-min.js:1:26) - at Object. (*enclosing-call-site-min.js:1:199) + at functionD (*/test/fixtures/source-map/enclosing-call-site-min.js:1:156) + at functionC (*/test/fixtures/source-map/enclosing-call-site-min.js:1:97) + at functionB (*/test/fixtures/source-map/enclosing-call-site-min.js:1:60) + at functionA (*/test/fixtures/source-map/enclosing-call-site-min.js:1:26) + at Object. (*/test/fixtures/source-map/enclosing-call-site-min.js:1:199) Error: an error! - at functionD (*enclosing-call-site.js:16:17) - at functionC (*enclosing-call-site.js:10:3) - at functionB (*enclosing-call-site.js:6:3) - at functionA (*enclosing-call-site.js:2:3) - at Object. (*enclosing-call-site.js:24:3) + at functionD (*/test/fixtures/source-map/enclosing-call-site.js:16:17) + at functionC (*/test/fixtures/source-map/enclosing-call-site.js:10:3) + at functionB (*/test/fixtures/source-map/enclosing-call-site.js:6:3) + at functionA (*/test/fixtures/source-map/enclosing-call-site.js:2:3) + at Object. (*/test/fixtures/source-map/enclosing-call-site.js:24:3) diff --git a/test/fixtures/source-map/output/source_map_disabled_by_process_api.snapshot b/test/fixtures/source-map/output/source_map_disabled_by_process_api.snapshot index 655cd6695e1116..f538904873393e 100644 --- a/test/fixtures/source-map/output/source_map_disabled_by_process_api.snapshot +++ b/test/fixtures/source-map/output/source_map_disabled_by_process_api.snapshot @@ -1,12 +1,12 @@ Error: an error! - at functionD (*enclosing-call-site-min.js:1:156) - at functionC (*enclosing-call-site-min.js:1:97) - at functionB (*enclosing-call-site-min.js:1:60) - at functionA (*enclosing-call-site-min.js:1:26) - at Object. (*enclosing-call-site-min.js:1:199) + at functionD (*/test/fixtures/source-map/enclosing-call-site-min.js:1:156) + at functionC (*/test/fixtures/source-map/enclosing-call-site-min.js:1:97) + at functionB (*/test/fixtures/source-map/enclosing-call-site-min.js:1:60) + at functionA (*/test/fixtures/source-map/enclosing-call-site-min.js:1:26) + at Object. (*/test/fixtures/source-map/enclosing-call-site-min.js:1:199) Error: an error! - at functionD (*enclosing-call-site.js:16:17) - at functionC (*enclosing-call-site.js:10:3) - at functionB (*enclosing-call-site.js:6:3) - at functionA (*enclosing-call-site.js:2:3) - at Object. (*enclosing-call-site.js:24:3) + at functionD (*/test/fixtures/source-map/enclosing-call-site.js:16:17) + at functionC (*/test/fixtures/source-map/enclosing-call-site.js:10:3) + at functionB (*/test/fixtures/source-map/enclosing-call-site.js:6:3) + at functionA (*/test/fixtures/source-map/enclosing-call-site.js:2:3) + at Object. (*/test/fixtures/source-map/enclosing-call-site.js:24:3) diff --git a/test/fixtures/source-map/output/source_map_enabled_by_api.snapshot b/test/fixtures/source-map/output/source_map_enabled_by_api.snapshot index 082b3f310ed4f9..9fe43a29865b35 100644 --- a/test/fixtures/source-map/output/source_map_enabled_by_api.snapshot +++ b/test/fixtures/source-map/output/source_map_enabled_by_api.snapshot @@ -1,12 +1,12 @@ Error: an error! - at functionD (*enclosing-call-site.js:16:17) - at functionC (*enclosing-call-site.js:10:3) - at functionB (*enclosing-call-site.js:6:3) - at functionA (*enclosing-call-site.js:2:3) - at Object. (*enclosing-call-site.js:24:3) + at functionD (*/test/fixtures/source-map/enclosing-call-site.js:16:17) + at functionC (*/test/fixtures/source-map/enclosing-call-site.js:10:3) + at functionB (*/test/fixtures/source-map/enclosing-call-site.js:6:3) + at functionA (*/test/fixtures/source-map/enclosing-call-site.js:2:3) + at Object. (*/test/fixtures/source-map/enclosing-call-site.js:24:3) Error: an error! - at functionD (*enclosing-call-site-min.js:1:156) - at functionC (*enclosing-call-site-min.js:1:97) - at functionB (*enclosing-call-site-min.js:1:60) - at functionA (*enclosing-call-site-min.js:1:26) - at Object. (*enclosing-call-site-min.js:1:199) + at functionD (*/test/fixtures/source-map/enclosing-call-site-min.js:1:156) + at functionC (*/test/fixtures/source-map/enclosing-call-site-min.js:1:97) + at functionB (*/test/fixtures/source-map/enclosing-call-site-min.js:1:60) + at functionA (*/test/fixtures/source-map/enclosing-call-site-min.js:1:26) + at Object. (*/test/fixtures/source-map/enclosing-call-site-min.js:1:199) diff --git a/test/fixtures/source-map/output/source_map_enabled_by_api_node_modules.snapshot b/test/fixtures/source-map/output/source_map_enabled_by_api_node_modules.snapshot index f46c21dbe42057..decc8ee3632f70 100644 --- a/test/fixtures/source-map/output/source_map_enabled_by_api_node_modules.snapshot +++ b/test/fixtures/source-map/output/source_map_enabled_by_api_node_modules.snapshot @@ -1,12 +1,12 @@ Error: an error! - at functionD (*node_modules*error-stack*enclosing-call-site.js:16:17) - at functionC (*node_modules*error-stack*enclosing-call-site.js:10:3) - at functionB (*node_modules*error-stack*enclosing-call-site.js:6:3) - at functionA (*node_modules*error-stack*enclosing-call-site.js:2:3) - at Object. (*node_modules*error-stack*enclosing-call-site.js:24:3) + at functionD (*/test/fixtures/source-map/node_modules/error-stack/enclosing-call-site.js:16:17) + at functionC (*/test/fixtures/source-map/node_modules/error-stack/enclosing-call-site.js:10:3) + at functionB (*/test/fixtures/source-map/node_modules/error-stack/enclosing-call-site.js:6:3) + at functionA (*/test/fixtures/source-map/node_modules/error-stack/enclosing-call-site.js:2:3) + at Object. (*/test/fixtures/source-map/node_modules/error-stack/enclosing-call-site.js:24:3) Error: an error! - at functionD (*node_modules*error-stack*enclosing-call-site-min.js:1:156) - at functionC (*node_modules*error-stack*enclosing-call-site-min.js:1:97) - at functionB (*node_modules*error-stack*enclosing-call-site-min.js:1:60) - at functionA (*node_modules*error-stack*enclosing-call-site-min.js:1:26) - at Object. (*node_modules*error-stack*enclosing-call-site-min.js:1:199) + at functionD (*/test/fixtures/source-map/node_modules/error-stack/enclosing-call-site-min.js:1:156) + at functionC (*/test/fixtures/source-map/node_modules/error-stack/enclosing-call-site-min.js:1:97) + at functionB (*/test/fixtures/source-map/node_modules/error-stack/enclosing-call-site-min.js:1:60) + at functionA (*/test/fixtures/source-map/node_modules/error-stack/enclosing-call-site-min.js:1:26) + at Object. (*/test/fixtures/source-map/node_modules/error-stack/enclosing-call-site-min.js:1:199) diff --git a/test/fixtures/source-map/output/source_map_enabled_by_process_api.snapshot b/test/fixtures/source-map/output/source_map_enabled_by_process_api.snapshot index 082b3f310ed4f9..9fe43a29865b35 100644 --- a/test/fixtures/source-map/output/source_map_enabled_by_process_api.snapshot +++ b/test/fixtures/source-map/output/source_map_enabled_by_process_api.snapshot @@ -1,12 +1,12 @@ Error: an error! - at functionD (*enclosing-call-site.js:16:17) - at functionC (*enclosing-call-site.js:10:3) - at functionB (*enclosing-call-site.js:6:3) - at functionA (*enclosing-call-site.js:2:3) - at Object. (*enclosing-call-site.js:24:3) + at functionD (*/test/fixtures/source-map/enclosing-call-site.js:16:17) + at functionC (*/test/fixtures/source-map/enclosing-call-site.js:10:3) + at functionB (*/test/fixtures/source-map/enclosing-call-site.js:6:3) + at functionA (*/test/fixtures/source-map/enclosing-call-site.js:2:3) + at Object. (*/test/fixtures/source-map/enclosing-call-site.js:24:3) Error: an error! - at functionD (*enclosing-call-site-min.js:1:156) - at functionC (*enclosing-call-site-min.js:1:97) - at functionB (*enclosing-call-site-min.js:1:60) - at functionA (*enclosing-call-site-min.js:1:26) - at Object. (*enclosing-call-site-min.js:1:199) + at functionD (*/test/fixtures/source-map/enclosing-call-site-min.js:1:156) + at functionC (*/test/fixtures/source-map/enclosing-call-site-min.js:1:97) + at functionB (*/test/fixtures/source-map/enclosing-call-site-min.js:1:60) + at functionA (*/test/fixtures/source-map/enclosing-call-site-min.js:1:26) + at Object. (*/test/fixtures/source-map/enclosing-call-site-min.js:1:199) diff --git a/test/fixtures/source-map/output/source_map_enclosing_function.snapshot b/test/fixtures/source-map/output/source_map_enclosing_function.snapshot index 976cd4fdbbc6e9..b60f988be3214e 100644 --- a/test/fixtures/source-map/output/source_map_enclosing_function.snapshot +++ b/test/fixtures/source-map/output/source_map_enclosing_function.snapshot @@ -1,13 +1,13 @@ -*enclosing-call-site.js:26 +*/test/fixtures/source-map/enclosing-call-site.js:26 throw err ^ Error: an error! - at functionD (*enclosing-call-site.js:16:17) - at functionC (*enclosing-call-site.js:10:3) - at functionB (*enclosing-call-site.js:6:3) - at functionA (*enclosing-call-site.js:2:3) - at Object. (*enclosing-call-site.js:24:3) + at functionD (*/test/fixtures/source-map/enclosing-call-site.js:16:17) + at functionC (*/test/fixtures/source-map/enclosing-call-site.js:10:3) + at functionB (*/test/fixtures/source-map/enclosing-call-site.js:6:3) + at functionA (*/test/fixtures/source-map/enclosing-call-site.js:2:3) + at Object. (*/test/fixtures/source-map/enclosing-call-site.js:24:3) Node.js * diff --git a/test/fixtures/source-map/output/source_map_eval.js b/test/fixtures/source-map/output/source_map_eval.js index 5492c179248180..6454096f58a5a6 100644 --- a/test/fixtures/source-map/output/source_map_eval.js +++ b/test/fixtures/source-map/output/source_map_eval.js @@ -6,5 +6,6 @@ Error.stackTraceLimit = 3; const fs = require('fs'); -const content = fs.readFileSync(require.resolve('../tabs.js'), 'utf8'); +const content = fs.readFileSync(require.resolve('../tabs-source-url.js'), 'utf8'); +// SourceURL magic comment is hardcoded in the source content. eval(content); diff --git a/test/fixtures/source-map/output/source_map_eval.snapshot b/test/fixtures/source-map/output/source_map_eval.snapshot index a4fcdb25282dfa..ff636e44063aa7 100644 --- a/test/fixtures/source-map/output/source_map_eval.snapshot +++ b/test/fixtures/source-map/output/source_map_eval.snapshot @@ -1,11 +1,11 @@ -*tabs.coffee:26 +*/synthesized/workspace/tabs-source-url.coffee:26 alert "I knew it!" ^ ReferenceError: alert is not defined - at Object.eval (*tabs.coffee:26:2) - at eval (*tabs.coffee:1:14) - at Object. (*output*source_map_eval.js:10:1) + at Object.eval (*/synthesized/workspace/tabs-source-url.coffee:26:2) + at eval (*/synthesized/workspace/tabs-source-url.coffee:1:14) + at Object. (*/test/fixtures/source-map/output/source_map_eval.js:11:1) Node.js * diff --git a/test/fixtures/source-map/output/source_map_no_source_file.snapshot b/test/fixtures/source-map/output/source_map_no_source_file.snapshot index cf9329747ba692..6d0e0cf6db727e 100644 --- a/test/fixtures/source-map/output/source_map_no_source_file.snapshot +++ b/test/fixtures/source-map/output/source_map_no_source_file.snapshot @@ -1,9 +1,9 @@ -*no-source.js:2 +*/test/fixtures/source-map/no-source.js:2 throw new Error('foo'); ^ Error: foo - at Throw (*file-not-exists.ts:2:9) - at Object. (*file-not-exists.ts:5:1) + at Throw (*/test/fixtures/source-map/file-not-exists.ts:2:9) + at Object. (*/test/fixtures/source-map/file-not-exists.ts:5:1) Node.js * diff --git a/test/fixtures/source-map/output/source_map_prepare_stack_trace.snapshot b/test/fixtures/source-map/output/source_map_prepare_stack_trace.snapshot index 9e9740a26fc34e..57bac36a2e5214 100644 --- a/test/fixtures/source-map/output/source_map_prepare_stack_trace.snapshot +++ b/test/fixtures/source-map/output/source_map_prepare_stack_trace.snapshot @@ -1,10 +1,10 @@ Error: an error! - at functionD (*enclosing-call-site.js:16:17) - at functionB (*enclosing-call-site.js:6:3) - at functionA (*enclosing-call-site.js:2:3) - at Object. (*enclosing-call-site.js:24:3) + at functionD (*/test/fixtures/source-map/enclosing-call-site.js:16:17) + at functionB (*/test/fixtures/source-map/enclosing-call-site.js:6:3) + at functionA (*/test/fixtures/source-map/enclosing-call-site.js:2:3) + at Object. (*/test/fixtures/source-map/enclosing-call-site.js:24:3) Error: an error! - at functionD (*enclosing-call-site-min.js:1:156) - at functionB (*enclosing-call-site-min.js:1:60) - at functionA (*enclosing-call-site-min.js:1:26) - at Object. (*enclosing-call-site-min.js:1:199) + at functionD (*/test/fixtures/source-map/enclosing-call-site-min.js:1:156) + at functionB (*/test/fixtures/source-map/enclosing-call-site-min.js:1:60) + at functionA (*/test/fixtures/source-map/enclosing-call-site-min.js:1:26) + at Object. (*/test/fixtures/source-map/enclosing-call-site-min.js:1:199) diff --git a/test/fixtures/source-map/output/source_map_reference_error_tabs.snapshot b/test/fixtures/source-map/output/source_map_reference_error_tabs.snapshot index 97d02f176c0cb7..2043bd0a88e897 100644 --- a/test/fixtures/source-map/output/source_map_reference_error_tabs.snapshot +++ b/test/fixtures/source-map/output/source_map_reference_error_tabs.snapshot @@ -1,10 +1,10 @@ -*tabs.coffee:26 +*/test/fixtures/source-map/tabs.coffee:26 alert "I knew it!" ^ ReferenceError: alert is not defined - at Object. (*tabs.coffee:26:2) - at Object. (*tabs.coffee:1:14) + at Object. (*/test/fixtures/source-map/tabs.coffee:26:2) + at Object. (*/test/fixtures/source-map/tabs.coffee:1:14) Node.js * diff --git a/test/fixtures/source-map/output/source_map_sourcemapping_url_string.snapshot b/test/fixtures/source-map/output/source_map_sourcemapping_url_string.snapshot index 6a109c904e1155..52d4e6a28ee5ce 100644 --- a/test/fixtures/source-map/output/source_map_sourcemapping_url_string.snapshot +++ b/test/fixtures/source-map/output/source_map_sourcemapping_url_string.snapshot @@ -1,3 +1,3 @@ Error: an exception. - at Object. (*typescript-sourcemapping_url_string.ts:3:7) + at Object. (*/test/fixtures/source-map/typescript-sourcemapping_url_string.ts:3:7) * diff --git a/test/fixtures/source-map/output/source_map_throw_async_stack_trace.snapshot b/test/fixtures/source-map/output/source_map_throw_async_stack_trace.snapshot index 8f7f0490587585..f53aec68ce8bb3 100644 --- a/test/fixtures/source-map/output/source_map_throw_async_stack_trace.snapshot +++ b/test/fixtures/source-map/output/source_map_throw_async_stack_trace.snapshot @@ -1,11 +1,11 @@ -*output*source_map_throw_async_stack_trace.mts:13 +*/test/fixtures/source-map/output/source_map_throw_async_stack_trace.mts:13 throw new Error('message') ^ Error: message - at Throw (*output*source_map_throw_async_stack_trace.mts:13:9) + at Throw (*/test/fixtures/source-map/output/source_map_throw_async_stack_trace.mts:13:9) at async Promise.all (index 3) - at async main (*output*source_map_throw_async_stack_trace.mts:17:3) + at async main (*/test/fixtures/source-map/output/source_map_throw_async_stack_trace.mts:17:3) Node.js * diff --git a/test/fixtures/source-map/output/source_map_throw_catch.snapshot b/test/fixtures/source-map/output/source_map_throw_catch.snapshot index 5eaffbfbf7874f..6e80e500c8cf17 100644 --- a/test/fixtures/source-map/output/source_map_throw_catch.snapshot +++ b/test/fixtures/source-map/output/source_map_throw_catch.snapshot @@ -1,4 +1,4 @@ reachable Error: an exception - at branch (*typescript-throw.ts:18:11) - at Object. (*typescript-throw.ts:24:1) + at branch (*/test/fixtures/source-map/typescript-throw.ts:18:11) + at Object. (*/test/fixtures/source-map/typescript-throw.ts:24:1) diff --git a/test/fixtures/source-map/output/source_map_throw_construct.snapshot b/test/fixtures/source-map/output/source_map_throw_construct.snapshot index 8618d4b51a46ec..dc28053240aa0b 100644 --- a/test/fixtures/source-map/output/source_map_throw_construct.snapshot +++ b/test/fixtures/source-map/output/source_map_throw_construct.snapshot @@ -1,11 +1,11 @@ -*output*source_map_throw_construct.mts:13 +*/test/fixtures/source-map/output/source_map_throw_construct.mts:13 throw new Error('message'); ^ Error: message - at new Foo (*output*source_map_throw_construct.mts:13:11) - at (*output*source_map_throw_construct.mts:17:1) + at new Foo (*/test/fixtures/source-map/output/source_map_throw_construct.mts:13:11) + at (*/test/fixtures/source-map/output/source_map_throw_construct.mts:17:1) * * * diff --git a/test/fixtures/source-map/output/source_map_throw_first_tick.snapshot b/test/fixtures/source-map/output/source_map_throw_first_tick.snapshot index fba8c95cc1103f..e129d73ef1581c 100644 --- a/test/fixtures/source-map/output/source_map_throw_first_tick.snapshot +++ b/test/fixtures/source-map/output/source_map_throw_first_tick.snapshot @@ -1,11 +1,11 @@ reachable -*typescript-throw.ts:18 +*/test/fixtures/source-map/typescript-throw.ts:18 throw Error('an exception'); ^ Error: an exception - at branch (*typescript-throw.ts:18:11) - at Object. (*typescript-throw.ts:24:1) + at branch (*/test/fixtures/source-map/typescript-throw.ts:18:11) + at Object. (*/test/fixtures/source-map/typescript-throw.ts:24:1) Node.js * diff --git a/test/fixtures/source-map/output/source_map_throw_icu.snapshot b/test/fixtures/source-map/output/source_map_throw_icu.snapshot index 425495062e6423..4b2853479b9576 100644 --- a/test/fixtures/source-map/output/source_map_throw_icu.snapshot +++ b/test/fixtures/source-map/output/source_map_throw_icu.snapshot @@ -1,10 +1,10 @@ -*icu.jsx:3 +*/test/fixtures/source-map/icu.jsx:3 ("あ 🐕 🐕", throw Error("an error")); ^ Error: an error - at Object.createElement (*icu.jsx:3:23) - at Object. (*icu.jsx:9:5) + at Object.createElement (*/test/fixtures/source-map/icu.jsx:3:23) + at Object. (*/test/fixtures/source-map/icu.jsx:9:5) Node.js * diff --git a/test/fixtures/source-map/output/source_map_throw_set_immediate.snapshot b/test/fixtures/source-map/output/source_map_throw_set_immediate.snapshot index ec9f1346ca5e0c..4cf4d52a16ea93 100644 --- a/test/fixtures/source-map/output/source_map_throw_set_immediate.snapshot +++ b/test/fixtures/source-map/output/source_map_throw_set_immediate.snapshot @@ -1,11 +1,11 @@ -*uglify-throw-original.js:5 +*/test/fixtures/source-map/uglify-throw-original.js:5 throw Error('goodbye'); ^ Error: goodbye - at Hello (*uglify-throw-original.js:5:9) - at Immediate. (*uglify-throw-original.js:9:3) + at Hello (*/test/fixtures/source-map/uglify-throw-original.js:5:9) + at Immediate. (*/test/fixtures/source-map/uglify-throw-original.js:9:3) * Node.js * diff --git a/test/fixtures/source-map/tabs-source-url.coffee b/test/fixtures/source-map/tabs-source-url.coffee new file mode 100644 index 00000000000000..7e73a605d32fc9 --- /dev/null +++ b/test/fixtures/source-map/tabs-source-url.coffee @@ -0,0 +1,34 @@ +# Assignment: +number = 42 +opposite = true + +# Conditions: +number = -42 if opposite + +# Functions: +square = (x) -> x * x + +# Arrays: +list = [1, 2, 3, 4, 5] + +# Objects: +math = + root: Math.sqrt + square: square + cube: (x) -> x * square x + +# Splats: +race = (winner, runners...) -> + print winner, runners + +# Existence: +if true + alert "I knew it!" + +# Array comprehensions: +cubes = (math.cube num for num in list) + +# To reproduce: +# cd test/fixtures/source-map +# npx --package=coffeescript@2.5.1 -- coffee -M --compile tabs-source-url.coffee +# sed -i -e "s/$(pwd | sed -e "s/\//\\\\\//g")/.\\/synthesized\\/workspace/g" tabs-source-url.js diff --git a/test/fixtures/source-map/tabs-source-url.js b/test/fixtures/source-map/tabs-source-url.js new file mode 100644 index 00000000000000..a4b43806a5f2f5 --- /dev/null +++ b/test/fixtures/source-map/tabs-source-url.js @@ -0,0 +1,61 @@ +// Generated by CoffeeScript 2.5.1 +(function() { + // Assignment: + var cubes, list, math, num, number, opposite, race, square; + + number = 42; + + opposite = true; + + if (opposite) { + // Conditions: + number = -42; + } + + // Functions: + square = function(x) { + return x * x; + }; + + // Arrays: + list = [1, 2, 3, 4, 5]; + + // Objects: + math = { + root: Math.sqrt, + square: square, + cube: function(x) { + return x * square(x); + } + }; + + // Splats: + race = function(winner, ...runners) { + return print(winner, runners); + }; + + // Existence: + if (true) { + alert("I knew it!"); + } + + // Array comprehensions: + cubes = (function() { + var i, len, results; + results = []; + for (i = 0, len = list.length; i < len; i++) { + num = list[i]; + results.push(math.cube(num)); + } + return results; + })(); + + // To reproduce: +// cd test/fixtures/source-map +// npx --package=coffeescript@2.5.1 -- coffee -M --compile tabs-source-url.coffee +// sed -i -e "s/$(pwd | sed -e "s/\//\\\\\//g")/.\\/synthesized\\/workspace/g" tabs-source-url.js + +}).call(this); + +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGFicy1zb3VyY2UtdXJsLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsidGFicy1zb3VyY2UtdXJsLmNvZmZlZSJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQWE7RUFBQTtBQUFBLE1BQUEsS0FBQSxFQUFBLElBQUEsRUFBQSxJQUFBLEVBQUEsR0FBQSxFQUFBLE1BQUEsRUFBQSxRQUFBLEVBQUEsSUFBQSxFQUFBOztFQUNiLE1BQUEsR0FBVzs7RUFDWCxRQUFBLEdBQVc7O0VBR1gsSUFBZ0IsUUFBaEI7O0lBQUEsTUFBQSxHQUFTLENBQUMsR0FBVjtHQUxhOzs7RUFRYixNQUFBLEdBQVMsUUFBQSxDQUFDLENBQUQsQ0FBQTtXQUFPLENBQUEsR0FBSTtFQUFYLEVBUkk7OztFQVdiLElBQUEsR0FBTyxDQUFDLENBQUQsRUFBSSxDQUFKLEVBQU8sQ0FBUCxFQUFVLENBQVYsRUFBYSxDQUFiLEVBWE07OztFQWNiLElBQUEsR0FDQztJQUFBLElBQUEsRUFBUSxJQUFJLENBQUMsSUFBYjtJQUNBLE1BQUEsRUFBUSxNQURSO0lBRUEsSUFBQSxFQUFRLFFBQUEsQ0FBQyxDQUFELENBQUE7YUFBTyxDQUFBLEdBQUksTUFBQSxDQUFPLENBQVA7SUFBWDtFQUZSLEVBZlk7OztFQW9CYixJQUFBLEdBQU8sUUFBQSxDQUFDLE1BQUQsRUFBQSxHQUFTLE9BQVQsQ0FBQTtXQUNOLEtBQUEsQ0FBTSxNQUFOLEVBQWMsT0FBZDtFQURNLEVBcEJNOzs7RUF3QmIsSUFBRyxJQUFIO0lBQ0MsS0FBQSxDQUFNLFlBQU4sRUFERDtHQXhCYTs7O0VBNEJiLEtBQUE7O0FBQVM7SUFBQSxLQUFBLHNDQUFBOzttQkFBQSxJQUFJLENBQUMsSUFBTCxDQUFVLEdBQVY7SUFBQSxDQUFBOzs7O0VBNUJJOzs7O0FBQUEiLCJzb3VyY2VzQ29udGVudCI6WyIjIEFzc2lnbm1lbnQ6XG5udW1iZXIgICA9IDQyXG5vcHBvc2l0ZSA9IHRydWVcblxuIyBDb25kaXRpb25zOlxubnVtYmVyID0gLTQyIGlmIG9wcG9zaXRlXG5cbiMgRnVuY3Rpb25zOlxuc3F1YXJlID0gKHgpIC0+IHggKiB4XG5cbiMgQXJyYXlzOlxubGlzdCA9IFsxLCAyLCAzLCA0LCA1XVxuXG4jIE9iamVjdHM6XG5tYXRoID1cblx0cm9vdDogICBNYXRoLnNxcnRcblx0c3F1YXJlOiBzcXVhcmVcblx0Y3ViZTogICAoeCkgLT4geCAqIHNxdWFyZSB4XG5cbiMgU3BsYXRzOlxucmFjZSA9ICh3aW5uZXIsIHJ1bm5lcnMuLi4pIC0+XG5cdHByaW50IHdpbm5lciwgcnVubmVyc1xuXG4jIEV4aXN0ZW5jZTpcbmlmIHRydWVcblx0YWxlcnQgXCJJIGtuZXcgaXQhXCJcblxuIyBBcnJheSBjb21wcmVoZW5zaW9uczpcbmN1YmVzID0gKG1hdGguY3ViZSBudW0gZm9yIG51bSBpbiBsaXN0KVxuXG4jIFRvIHJlcHJvZHVjZTpcbiMgY2QgdGVzdC9maXh0dXJlcy9zb3VyY2UtbWFwXG4jIG5weCAtLXBhY2thZ2U9Y29mZmVlc2NyaXB0QDIuNS4xIC0tIGNvZmZlZSAtTSAtLWNvbXBpbGUgdGFicy1zb3VyY2UtdXJsLmNvZmZlZVxuIyBzZWQgLWkgLWUgXCJzLyQocHdkIHwgc2VkIC1lIFwicy9cXC8vXFxcXFxcXFxcXC8vZ1wiKS8uXFxcXC9zeW50aGVzaXplZFxcXFwvd29ya3NwYWNlL2dcIiB0YWJzLXNvdXJjZS11cmwuanNcbiJdfQ== +//# sourceURL=./synthesized/workspace/tabs-source-url.coffee \ No newline at end of file diff --git a/test/fixtures/test-runner/coverage/bar.mts b/test/fixtures/test-runner/coverage/bar.mts new file mode 100644 index 00000000000000..19251773e5ead3 --- /dev/null +++ b/test/fixtures/test-runner/coverage/bar.mts @@ -0,0 +1,3 @@ +export default function bar() { + return 'original bar'; +} diff --git a/test/fixtures/test-runner/coverage/foo.mts b/test/fixtures/test-runner/coverage/foo.mts new file mode 100644 index 00000000000000..a66961a27a9c26 --- /dev/null +++ b/test/fixtures/test-runner/coverage/foo.mts @@ -0,0 +1,3 @@ +import bar from './bar.mts'; + +export const foo = () => bar(); diff --git a/test/fixtures/test-runner/output/typescript-coverage.mts b/test/fixtures/test-runner/output/typescript-coverage.mts new file mode 100644 index 00000000000000..c26ddcac9b33f9 --- /dev/null +++ b/test/fixtures/test-runner/output/typescript-coverage.mts @@ -0,0 +1,25 @@ +import assert from 'node:assert/strict'; +import { before, describe, it, mock } from 'node:test'; + +describe('foo', { concurrency: true }, () => { + let barMock = mock.fn(); + let foo; + + before(async () => { + const barNamedExports = await import('../coverage/bar.mts') + .then(({ default: _, ...rest }) => rest); + + mock.module('../coverage/bar.mts', { + defaultExport: barMock, + namedExports: barNamedExports, + }); + + ({ foo } = await import('../coverage/foo.mts')); + }); + + it('should do the thing', () => { + barMock.mock.mockImplementationOnce(() => 42); + + assert.equal(foo(), 42); + }); +}); diff --git a/test/fixtures/test-runner/output/typescript-coverage.snapshot b/test/fixtures/test-runner/output/typescript-coverage.snapshot new file mode 100644 index 00000000000000..eaeba2bfa11b12 --- /dev/null +++ b/test/fixtures/test-runner/output/typescript-coverage.snapshot @@ -0,0 +1,39 @@ +TAP version 13 +# Subtest: foo + # Subtest: should do the thing + ok 1 - should do the thing + --- + duration_ms: * + type: 'test' + ... + 1..1 +ok 1 - foo + --- + duration_ms: * + type: 'suite' + ... +1..1 +# tests 1 +# suites 1 +# pass 1 +# fail 0 +# cancelled 0 +# skipped 0 +# todo 0 +# duration_ms * +# start of coverage report +# ---------------------------------------------------------------------------- +# file | line % | branch % | funcs % | uncovered lines +# ---------------------------------------------------------------------------- +# test | | | | +# fixtures | | | | +# test-runner | | | | +# coverage | | | | +# bar.mts | 0.00 | 100.00 | 100.00 | 1-3 +# foo.mts | 100.00 | 100.00 | 100.00 | +# output | | | | +# typescript-coverage.mts | 100.00 | 100.00 | 100.00 | +# ---------------------------------------------------------------------------- +# all files | 85.29 | 100.00 | 85.71 | +# ---------------------------------------------------------------------------- +# end of coverage report diff --git a/test/fixtures/wpt/README.md b/test/fixtures/wpt/README.md index d6b9c918150527..639b2093030348 100644 --- a/test/fixtures/wpt/README.md +++ b/test/fixtures/wpt/README.md @@ -23,7 +23,7 @@ Last update: - html/webappapis/microtask-queuing: https://github.com/web-platform-tests/wpt/tree/2c5c3c4c27/html/webappapis/microtask-queuing - html/webappapis/structured-clone: https://github.com/web-platform-tests/wpt/tree/47d3fb280c/html/webappapis/structured-clone - html/webappapis/timers: https://github.com/web-platform-tests/wpt/tree/5873f2d8f1/html/webappapis/timers -- interfaces: https://github.com/web-platform-tests/wpt/tree/e90ece61d6/interfaces +- interfaces: https://github.com/web-platform-tests/wpt/tree/e1b27be06b/interfaces - performance-timeline: https://github.com/web-platform-tests/wpt/tree/94caab7038/performance-timeline - resource-timing: https://github.com/web-platform-tests/wpt/tree/22d38586d0/resource-timing - resources: https://github.com/web-platform-tests/wpt/tree/1e140d63ec/resources @@ -32,7 +32,7 @@ Last update: - user-timing: https://github.com/web-platform-tests/wpt/tree/5ae85bf826/user-timing - wasm/jsapi: https://github.com/web-platform-tests/wpt/tree/cde25e7e3c/wasm/jsapi - wasm/webapi: https://github.com/web-platform-tests/wpt/tree/fd1b23eeaa/wasm/webapi -- WebCryptoAPI: https://github.com/web-platform-tests/wpt/tree/b48efd681e/WebCryptoAPI +- WebCryptoAPI: https://github.com/web-platform-tests/wpt/tree/591c95ce61/WebCryptoAPI - webidl/ecmascript-binding/es-exceptions: https://github.com/web-platform-tests/wpt/tree/a370aad338/webidl/ecmascript-binding/es-exceptions - webmessaging/broadcastchannel: https://github.com/web-platform-tests/wpt/tree/6495c91853/webmessaging/broadcastchannel - webstorage: https://github.com/web-platform-tests/wpt/tree/1291340aaa/webstorage diff --git a/test/fixtures/wpt/WebCryptoAPI/idlharness.https.any.js b/test/fixtures/wpt/WebCryptoAPI/idlharness.https.any.js index ae65eb49f2120e..5ddf7eab6dba21 100644 --- a/test/fixtures/wpt/WebCryptoAPI/idlharness.https.any.js +++ b/test/fixtures/wpt/WebCryptoAPI/idlharness.https.any.js @@ -5,7 +5,7 @@ // https://w3c.github.io/webcrypto/Overview.html idl_test( - ['WebCryptoAPI'], + ['webcrypto'], ['html', 'dom'], idl_array => { idl_array.add_objects({ diff --git a/test/fixtures/wpt/interfaces/dom.idl b/test/fixtures/wpt/interfaces/dom.idl index 72d61f5cfd80ad..253e7bf913eba9 100644 --- a/test/fixtures/wpt/interfaces/dom.idl +++ b/test/fixtures/wpt/interfaces/dom.idl @@ -110,6 +110,7 @@ Document includes NonElementParentNode; DocumentFragment includes NonElementParentNode; interface mixin DocumentOrShadowRoot { + readonly attribute CustomElementRegistry? customElementRegistry; }; Document includes DocumentOrShadowRoot; ShadowRoot includes DocumentOrShadowRoot; @@ -120,9 +121,11 @@ interface mixin ParentNode { readonly attribute Element? lastElementChild; readonly attribute unsigned long childElementCount; - [CEReactions, Unscopable] undefined prepend((Node or TrustedScript or DOMString)... nodes); - [CEReactions, Unscopable] undefined append((Node or TrustedScript or DOMString)... nodes); - [CEReactions, Unscopable] undefined replaceChildren((Node or TrustedScript or DOMString)... nodes); + [CEReactions, Unscopable] undefined prepend((Node or DOMString)... nodes); + [CEReactions, Unscopable] undefined append((Node or DOMString)... nodes); + [CEReactions, Unscopable] undefined replaceChildren((Node or DOMString)... nodes); + + [CEReactions] undefined moveBefore(Node node, Node? child); Element? querySelector(DOMString selectors); [NewObject] NodeList querySelectorAll(DOMString selectors); @@ -139,9 +142,9 @@ Element includes NonDocumentTypeChildNode; CharacterData includes NonDocumentTypeChildNode; interface mixin ChildNode { - [CEReactions, Unscopable] undefined before((Node or TrustedScript or DOMString)... nodes); - [CEReactions, Unscopable] undefined after((Node or TrustedScript or DOMString)... nodes); - [CEReactions, Unscopable] undefined replaceWith((Node or TrustedScript or DOMString)... nodes); + [CEReactions, Unscopable] undefined before((Node or DOMString)... nodes); + [CEReactions, Unscopable] undefined after((Node or DOMString)... nodes); + [CEReactions, Unscopable] undefined replaceWith((Node or DOMString)... nodes); [CEReactions, Unscopable] undefined remove(); }; DocumentType includes ChildNode; @@ -237,7 +240,7 @@ interface Node : EventTarget { [CEReactions] attribute DOMString? textContent; [CEReactions] undefined normalize(); - [CEReactions, NewObject] Node cloneNode(optional boolean deep = false); + [CEReactions, NewObject] Node cloneNode(optional boolean subtree = false); boolean isEqualNode(Node? otherNode); boolean isSameNode(Node? otherNode); // legacy alias of === @@ -291,7 +294,7 @@ interface Document : Node { [NewObject] Comment createComment(DOMString data); [NewObject] ProcessingInstruction createProcessingInstruction(DOMString target, DOMString data); - [CEReactions, NewObject] Node importNode(Node node, optional boolean deep = false); + [CEReactions, NewObject] Node importNode(Node node, optional (boolean or ImportNodeOptions) options = false); [CEReactions] Node adoptNode(Node node); [NewObject] Attr createAttribute(DOMString localName); @@ -310,9 +313,15 @@ interface Document : Node { interface XMLDocument : Document {}; dictionary ElementCreationOptions { + CustomElementRegistry customElementRegistry; DOMString is; }; +dictionary ImportNodeOptions { + CustomElementRegistry customElementRegistry; + boolean selfOnly = false; +}; + [Exposed=Window] interface DOMImplementation { [NewObject] DocumentType createDocumentType(DOMString qualifiedName, DOMString publicId, DOMString systemId); @@ -342,6 +351,7 @@ interface ShadowRoot : DocumentFragment { readonly attribute boolean clonable; readonly attribute boolean serializable; readonly attribute Element host; + attribute EventHandler onslotchange; }; @@ -382,6 +392,8 @@ interface Element : Node { ShadowRoot attachShadow(ShadowRootInit init); readonly attribute ShadowRoot? shadowRoot; + readonly attribute CustomElementRegistry? customElementRegistry; + Element? closest(DOMString selectors); boolean matches(DOMString selectors); boolean webkitMatchesSelector(DOMString selectors); // legacy alias of .matches @@ -400,6 +412,7 @@ dictionary ShadowRootInit { SlotAssignmentMode slotAssignment = "named"; boolean clonable = false; boolean serializable = false; + CustomElementRegistry customElementRegistry; }; [Exposed=Window, diff --git a/test/fixtures/wpt/interfaces/html.idl b/test/fixtures/wpt/interfaces/html.idl index 4d6c0229bc1392..9c84e6a67efa4f 100644 --- a/test/fixtures/wpt/interfaces/html.idl +++ b/test/fixtures/wpt/interfaces/html.idl @@ -125,6 +125,7 @@ interface HTMLElement : Element { [CEReactions] attribute boolean spellcheck; [CEReactions] attribute DOMString writingSuggestions; [CEReactions] attribute DOMString autocapitalize; + [CEReactions] attribute boolean autocorrect; [CEReactions] attribute [LegacyNullToEmptyString] DOMString innerText; [CEReactions] attribute [LegacyNullToEmptyString] DOMString outerText; @@ -132,12 +133,20 @@ interface HTMLElement : Element { ElementInternals attachInternals(); // The popover API - undefined showPopover(); + undefined showPopover(optional ShowPopoverOptions options = {}); undefined hidePopover(); - boolean togglePopover(optional boolean force); + boolean togglePopover(optional (TogglePopoverOptions or boolean) options = {}); [CEReactions] attribute DOMString? popover; }; +dictionary ShowPopoverOptions { + HTMLElement source; +}; + +dictionary TogglePopoverOptions : ShowPopoverOptions { + boolean force; +}; + HTMLElement includes GlobalEventHandlers; HTMLElement includes ElementContentEditable; HTMLElement includes HTMLOrSVGElement; @@ -880,10 +889,12 @@ interface HTMLInputElement : HTMLElement { [HTMLConstructor] constructor(); [CEReactions] attribute DOMString accept; + [CEReactions] attribute boolean alpha; [CEReactions] attribute DOMString alt; [CEReactions] attribute DOMString autocomplete; [CEReactions] attribute boolean defaultChecked; attribute boolean checked; + [CEReactions] attribute DOMString colorSpace; [CEReactions] attribute DOMString dirName; [CEReactions] attribute boolean disabled; readonly attribute HTMLFormElement? form; @@ -946,6 +957,8 @@ HTMLInputElement includes PopoverInvokerElement; interface HTMLButtonElement : HTMLElement { [HTMLConstructor] constructor(); + [CEReactions] attribute DOMString command; + [CEReactions] attribute Element? commandForElement; [CEReactions] attribute boolean disabled; readonly attribute HTMLFormElement? form; [CEReactions] attribute USVString formAction; @@ -1211,9 +1224,11 @@ interface HTMLDialogElement : HTMLElement { [CEReactions] attribute boolean open; attribute DOMString returnValue; + [CEReactions] attribute DOMString closedBy; [CEReactions] undefined show(); [CEReactions] undefined showModal(); [CEReactions] undefined close(optional DOMString returnValue); + [CEReactions] undefined requestClose(optional DOMString returnValue); }; [Exposed=Window] @@ -1246,6 +1261,7 @@ interface HTMLTemplateElement : HTMLElement { [CEReactions] attribute boolean shadowRootDelegatesFocus; [CEReactions] attribute boolean shadowRootClonable; [CEReactions] attribute boolean shadowRootSerializable; + [CEReactions] attribute DOMString shadowRootCustomElementRegistry; }; [Exposed=Window] @@ -1292,12 +1308,15 @@ typedef (HTMLOrSVGImageElement or enum PredefinedColorSpace { "srgb", "display-p3" }; +enum CanvasColorType { "unorm8", "float16" }; + enum CanvasFillRule { "nonzero", "evenodd" }; dictionary CanvasRenderingContext2DSettings { boolean alpha = true; boolean desynchronized = false; PredefinedColorSpace colorSpace = "srgb"; + CanvasColorType colorType = "unorm8"; boolean willReadFrequently = false; }; @@ -1307,9 +1326,8 @@ enum ImageSmoothingQuality { "low", "medium", "high" }; interface CanvasRenderingContext2D { // back-reference to the canvas readonly attribute HTMLCanvasElement canvas; - - CanvasRenderingContext2DSettings getContextAttributes(); }; +CanvasRenderingContext2D includes CanvasSettings; CanvasRenderingContext2D includes CanvasState; CanvasRenderingContext2D includes CanvasTransform; CanvasRenderingContext2D includes CanvasCompositing; @@ -1327,6 +1345,11 @@ CanvasRenderingContext2D includes CanvasPathDrawingStyles; CanvasRenderingContext2D includes CanvasTextDrawingStyles; CanvasRenderingContext2D includes CanvasPath; +interface mixin CanvasSettings { + // settings + CanvasRenderingContext2DSettings getContextAttributes(); +}; + interface mixin CanvasState { // state undefined save(); // push state on state stack @@ -1411,8 +1434,6 @@ interface mixin CanvasDrawPath { interface mixin CanvasUserInterface { undefined drawFocusIfNeeded(Element element); undefined drawFocusIfNeeded(Path2D path, Element element); - undefined scrollPathIntoView(); - undefined scrollPathIntoView(Path2D path); }; interface mixin CanvasText { @@ -1432,10 +1453,10 @@ interface mixin CanvasDrawImage { interface mixin CanvasImageData { // pixel manipulation ImageData createImageData([EnforceRange] long sw, [EnforceRange] long sh, optional ImageDataSettings settings = {}); - ImageData createImageData(ImageData imagedata); + ImageData createImageData(ImageData imageData); ImageData getImageData([EnforceRange] long sx, [EnforceRange] long sy, [EnforceRange] long sw, [EnforceRange] long sh, optional ImageDataSettings settings = {}); - undefined putImageData(ImageData imagedata, [EnforceRange] long dx, [EnforceRange] long dy); - undefined putImageData(ImageData imagedata, [EnforceRange] long dx, [EnforceRange] long dy, [EnforceRange] long dirtyX, [EnforceRange] long dirtyY, [EnforceRange] long dirtyWidth, [EnforceRange] long dirtyHeight); + undefined putImageData(ImageData imageData, [EnforceRange] long dx, [EnforceRange] long dy); + undefined putImageData(ImageData imageData, [EnforceRange] long dx, [EnforceRange] long dy, [EnforceRange] long dirtyX, [EnforceRange] long dirtyY, [EnforceRange] long dirtyWidth, [EnforceRange] long dirtyHeight); }; enum CanvasLineCap { "butt", "round", "square" }; @@ -1463,6 +1484,7 @@ interface mixin CanvasPathDrawingStyles { interface mixin CanvasTextDrawingStyles { // text + attribute DOMString lang; // (default: "inherit") attribute DOMString font; // (default 10px sans-serif) attribute CanvasTextAlign textAlign; // (default: "start") attribute CanvasTextBaseline textBaseline; // (default: "alphabetic") @@ -1520,22 +1542,6 @@ interface TextMetrics { readonly attribute double ideographicBaseline; }; -dictionary ImageDataSettings { - PredefinedColorSpace colorSpace; -}; - -[Exposed=(Window,Worker), - Serializable] -interface ImageData { - constructor(unsigned long sw, unsigned long sh, optional ImageDataSettings settings = {}); - constructor(Uint8ClampedArray data, unsigned long sw, optional unsigned long sh, optional ImageDataSettings settings = {}); - - readonly attribute unsigned long width; - readonly attribute unsigned long height; - readonly attribute Uint8ClampedArray data; - readonly attribute PredefinedColorSpace colorSpace; -}; - [Exposed=(Window,Worker)] interface Path2D { constructor(optional (Path2D or DOMString) path); @@ -1583,6 +1589,7 @@ interface OffscreenCanvasRenderingContext2D { readonly attribute OffscreenCanvas canvas; }; +OffscreenCanvasRenderingContext2D includes CanvasSettings; OffscreenCanvasRenderingContext2D includes CanvasState; OffscreenCanvasRenderingContext2D includes CanvasTransform; OffscreenCanvasRenderingContext2D includes CanvasCompositing; @@ -1601,11 +1608,14 @@ OffscreenCanvasRenderingContext2D includes CanvasPath; [Exposed=Window] interface CustomElementRegistry { + constructor(); + [CEReactions] undefined define(DOMString name, CustomElementConstructor constructor, optional ElementDefinitionOptions options = {}); (CustomElementConstructor or undefined) get(DOMString name); DOMString? getName(CustomElementConstructor constructor); Promise whenDefined(DOMString name); [CEReactions] undefined upgrade(Node root); + undefined initialize(Node root); }; callback CustomElementConstructor = HTMLElement (); @@ -1691,6 +1701,18 @@ dictionary ToggleEventInit : EventInit { DOMString newState = ""; }; +[Exposed=Window] +interface CommandEvent : Event { + constructor(DOMString type, optional CommandEventInit eventInitDict = {}); + readonly attribute Element? source; + readonly attribute DOMString command; +}; + +dictionary CommandEventInit : EventInit { + Element? source = null; + DOMString command = ""; +}; + dictionary FocusOptions { boolean preventScroll = false; boolean focusVisible; @@ -1976,6 +1998,7 @@ interface NavigateEvent : Event { readonly attribute DOMString? downloadRequest; readonly attribute any info; readonly attribute boolean hasUAVisualTransition; + readonly attribute Element? sourceElement; undefined intercept(optional NavigationInterceptOptions options = {}); undefined scroll(); @@ -1992,6 +2015,7 @@ dictionary NavigateEventInit : EventInit { DOMString? downloadRequest = null; any info; boolean hasUAVisualTransition = false; + Element? sourceElement = null; }; dictionary NavigationInterceptOptions { @@ -2108,10 +2132,10 @@ interface NotRestoredReasonDetails { [Exposed=Window] interface NotRestoredReasons { - readonly attribute DOMString? src; + readonly attribute USVString? src; readonly attribute DOMString? id; readonly attribute DOMString? name; - readonly attribute DOMString? url; + readonly attribute USVString? url; readonly attribute FrozenArray? reasons; readonly attribute FrozenArray? children; [Default] object toJSON(); @@ -2174,6 +2198,7 @@ interface mixin GlobalEventHandlers { attribute EventHandler onchange; attribute EventHandler onclick; attribute EventHandler onclose; + attribute EventHandler oncommand; attribute EventHandler oncontextlost; attribute EventHandler oncontextmenu; attribute EventHandler oncontextrestored; @@ -2332,6 +2357,13 @@ partial interface Range { [CEReactions, NewObject] DocumentFragment createContextualFragment((TrustedHTML or DOMString) string); }; +[Exposed=Window] +interface XMLSerializer { + constructor(); + + DOMString serializeToString(Node root); +}; + [Exposed=Window] interface Navigator { // objects implementing this interface also implement the interfaces given below @@ -2422,6 +2454,28 @@ interface MimeType { readonly attribute Plugin enabledPlugin; }; +typedef (Uint8ClampedArray or Float16Array) ImageDataArray; + +enum ImageDataPixelFormat { "rgba-unorm8", "rgba-float16" }; + +dictionary ImageDataSettings { + PredefinedColorSpace colorSpace; + ImageDataPixelFormat pixelFormat = "rgba-unorm8"; +}; + +[Exposed=(Window,Worker), + Serializable] +interface ImageData { + constructor(unsigned long sw, unsigned long sh, optional ImageDataSettings settings = {}); + constructor(ImageDataArray data, unsigned long sw, optional unsigned long sh, optional ImageDataSettings settings = {}); + + readonly attribute unsigned long width; + readonly attribute unsigned long height; + readonly attribute ImageDataArray data; + readonly attribute ImageDataPixelFormat pixelFormat; + readonly attribute PredefinedColorSpace colorSpace; +}; + [Exposed=(Window,Worker), Serializable, Transferable] interface ImageBitmap { readonly attribute unsigned long width; @@ -2511,6 +2565,11 @@ interface MessageChannel { readonly attribute MessagePort port2; }; +interface mixin MessageEventTarget { + attribute EventHandler onmessage; + attribute EventHandler onmessageerror; +}; + [Exposed=(Window,Worker,AudioWorklet), Transferable] interface MessagePort : EventTarget { undefined postMessage(any message, sequence transfer); @@ -2519,11 +2578,11 @@ interface MessagePort : EventTarget { undefined close(); // event handlers - attribute EventHandler onmessage; - attribute EventHandler onmessageerror; attribute EventHandler onclose; }; +MessagePort includes MessageEventTarget; + dictionary StructuredSerializeOptions { sequence transfer = []; }; @@ -2562,11 +2621,10 @@ interface DedicatedWorkerGlobalScope : WorkerGlobalScope { undefined postMessage(any message, optional StructuredSerializeOptions options = {}); undefined close(); - - attribute EventHandler onmessage; - attribute EventHandler onmessageerror; }; +DedicatedWorkerGlobalScope includes MessageEventTarget; + [Global=(Worker,SharedWorker),Exposed=SharedWorker] interface SharedWorkerGlobalScope : WorkerGlobalScope { [Replaceable] readonly attribute DOMString name; @@ -2588,8 +2646,6 @@ interface Worker : EventTarget { undefined postMessage(any message, sequence transfer); undefined postMessage(any message, optional StructuredSerializeOptions options = {}); - attribute EventHandler onmessage; - attribute EventHandler onmessageerror; }; dictionary WorkerOptions { @@ -2601,6 +2657,7 @@ dictionary WorkerOptions { enum WorkerType { "classic", "module" }; Worker includes AbstractWorker; +Worker includes MessageEventTarget; [Exposed=Window] interface SharedWorker : EventTarget { diff --git a/test/fixtures/wpt/interfaces/resource-timing.idl b/test/fixtures/wpt/interfaces/resource-timing.idl index 33fed05b756838..66f2841d744af3 100644 --- a/test/fixtures/wpt/interfaces/resource-timing.idl +++ b/test/fixtures/wpt/interfaces/resource-timing.idl @@ -18,6 +18,7 @@ interface PerformanceResourceTiming : PerformanceEntry { readonly attribute DOMHighResTimeStamp connectEnd; readonly attribute DOMHighResTimeStamp secureConnectionStart; readonly attribute DOMHighResTimeStamp requestStart; + readonly attribute DOMHighResTimeStamp finalResponseHeadersStart; readonly attribute DOMHighResTimeStamp firstInterimResponseStart; readonly attribute DOMHighResTimeStamp responseStart; readonly attribute DOMHighResTimeStamp responseEnd; diff --git a/test/fixtures/wpt/interfaces/urlpattern.idl b/test/fixtures/wpt/interfaces/urlpattern.idl new file mode 100644 index 00000000000000..ca9fb979d22939 --- /dev/null +++ b/test/fixtures/wpt/interfaces/urlpattern.idl @@ -0,0 +1,63 @@ +// GENERATED CONTENT - DO NOT EDIT +// Content was automatically extracted by Reffy into webref +// (https://github.com/w3c/webref) +// Source: URL Pattern Standard (https://urlpattern.spec.whatwg.org/) + +typedef (USVString or URLPatternInit) URLPatternInput; + +[Exposed=(Window,Worker)] +interface URLPattern { + constructor(URLPatternInput input, USVString baseURL, optional URLPatternOptions options = {}); + constructor(optional URLPatternInput input = {}, optional URLPatternOptions options = {}); + + boolean test(optional URLPatternInput input = {}, optional USVString baseURL); + + URLPatternResult? exec(optional URLPatternInput input = {}, optional USVString baseURL); + + readonly attribute USVString protocol; + readonly attribute USVString username; + readonly attribute USVString password; + readonly attribute USVString hostname; + readonly attribute USVString port; + readonly attribute USVString pathname; + readonly attribute USVString search; + readonly attribute USVString hash; + + readonly attribute boolean hasRegExpGroups; +}; + +dictionary URLPatternInit { + USVString protocol; + USVString username; + USVString password; + USVString hostname; + USVString port; + USVString pathname; + USVString search; + USVString hash; + USVString baseURL; +}; + +dictionary URLPatternOptions { + boolean ignoreCase = false; +}; + +dictionary URLPatternResult { + sequence inputs; + + URLPatternComponentResult protocol; + URLPatternComponentResult username; + URLPatternComponentResult password; + URLPatternComponentResult hostname; + URLPatternComponentResult port; + URLPatternComponentResult pathname; + URLPatternComponentResult search; + URLPatternComponentResult hash; +}; + +dictionary URLPatternComponentResult { + USVString input; + record groups; +}; + +typedef (USVString or URLPatternInit or URLPattern) URLPatternCompatible; diff --git a/test/fixtures/wpt/interfaces/user-timing.idl b/test/fixtures/wpt/interfaces/user-timing.idl index 28ee8aac2b19a6..fc6d30822588b1 100644 --- a/test/fixtures/wpt/interfaces/user-timing.idl +++ b/test/fixtures/wpt/interfaces/user-timing.idl @@ -1,7 +1,7 @@ // GENERATED CONTENT - DO NOT EDIT // Content was automatically extracted by Reffy into webref // (https://github.com/w3c/webref) -// Source: User Timing Level 3 (https://w3c.github.io/user-timing/) +// Source: User Timing (https://w3c.github.io/user-timing/) dictionary PerformanceMarkOptions { any detail; diff --git a/test/fixtures/wpt/interfaces/WebCryptoAPI.idl b/test/fixtures/wpt/interfaces/webcrypto.idl similarity index 67% rename from test/fixtures/wpt/interfaces/WebCryptoAPI.idl rename to test/fixtures/wpt/interfaces/webcrypto.idl index ae85c1cfe4684f..ff7a89cd0d51be 100644 --- a/test/fixtures/wpt/interfaces/WebCryptoAPI.idl +++ b/test/fixtures/wpt/interfaces/webcrypto.idl @@ -42,52 +42,77 @@ enum KeyFormat { "raw", "spki", "pkcs8", "jwk" }; [SecureContext,Exposed=(Window,Worker)] interface SubtleCrypto { - Promise encrypt(AlgorithmIdentifier algorithm, - CryptoKey key, - BufferSource data); - Promise decrypt(AlgorithmIdentifier algorithm, - CryptoKey key, - BufferSource data); - Promise sign(AlgorithmIdentifier algorithm, - CryptoKey key, - BufferSource data); - Promise verify(AlgorithmIdentifier algorithm, - CryptoKey key, - BufferSource signature, - BufferSource data); - Promise digest(AlgorithmIdentifier algorithm, - BufferSource data); - - Promise generateKey(AlgorithmIdentifier algorithm, - boolean extractable, - sequence keyUsages ); - Promise deriveKey(AlgorithmIdentifier algorithm, - CryptoKey baseKey, - AlgorithmIdentifier derivedKeyType, - boolean extractable, - sequence keyUsages ); - Promise deriveBits(AlgorithmIdentifier algorithm, - CryptoKey baseKey, - optional unsigned long? length = null); - - Promise importKey(KeyFormat format, - (BufferSource or JsonWebKey) keyData, - AlgorithmIdentifier algorithm, - boolean extractable, - sequence keyUsages ); - Promise exportKey(KeyFormat format, CryptoKey key); - - Promise wrapKey(KeyFormat format, - CryptoKey key, - CryptoKey wrappingKey, - AlgorithmIdentifier wrapAlgorithm); - Promise unwrapKey(KeyFormat format, - BufferSource wrappedKey, - CryptoKey unwrappingKey, - AlgorithmIdentifier unwrapAlgorithm, - AlgorithmIdentifier unwrappedKeyAlgorithm, - boolean extractable, - sequence keyUsages ); + Promise encrypt( + AlgorithmIdentifier algorithm, + CryptoKey key, + BufferSource data + ); + Promise decrypt( + AlgorithmIdentifier algorithm, + CryptoKey key, + BufferSource data + ); + Promise sign( + AlgorithmIdentifier algorithm, + CryptoKey key, + BufferSource data + ); + Promise verify( + AlgorithmIdentifier algorithm, + CryptoKey key, + BufferSource signature, + BufferSource data + ); + Promise digest( + AlgorithmIdentifier algorithm, + BufferSource data + ); + + Promise<(CryptoKey or CryptoKeyPair)> generateKey( + AlgorithmIdentifier algorithm, + boolean extractable, + sequence keyUsages + ); + Promise deriveKey( + AlgorithmIdentifier algorithm, + CryptoKey baseKey, + AlgorithmIdentifier derivedKeyType, + boolean extractable, + sequence keyUsages + ); + Promise deriveBits( + AlgorithmIdentifier algorithm, + CryptoKey baseKey, + optional unsigned long? length = null + ); + + Promise importKey( + KeyFormat format, + (BufferSource or JsonWebKey) keyData, + AlgorithmIdentifier algorithm, + boolean extractable, + sequence keyUsages + ); + Promise<(ArrayBuffer or JsonWebKey)> exportKey( + KeyFormat format, + CryptoKey key + ); + + Promise wrapKey( + KeyFormat format, + CryptoKey key, + CryptoKey wrappingKey, + AlgorithmIdentifier wrapAlgorithm + ); + Promise unwrapKey( + KeyFormat format, + BufferSource wrappedKey, + CryptoKey unwrappingKey, + AlgorithmIdentifier unwrapAlgorithm, + AlgorithmIdentifier unwrappedKeyAlgorithm, + boolean extractable, + sequence keyUsages + ); }; dictionary RsaOtherPrimesInfo { diff --git a/test/fixtures/wpt/versions.json b/test/fixtures/wpt/versions.json index 77cc8d9726dee6..bc92634f4ef367 100644 --- a/test/fixtures/wpt/versions.json +++ b/test/fixtures/wpt/versions.json @@ -52,7 +52,7 @@ "path": "html/webappapis/timers" }, "interfaces": { - "commit": "e90ece61d6e7ff84a0dc9c496588690e6a61cb17", + "commit": "e1b27be06b43787a001b7297c4e0fabdd276560f", "path": "interfaces" }, "performance-timeline": { @@ -88,7 +88,7 @@ "path": "wasm/webapi" }, "WebCryptoAPI": { - "commit": "b48efd681ea3a5b0daa6b866c3bb54bec895037b", + "commit": "591c95ce6174690b92833cd92859ce2807714591", "path": "WebCryptoAPI" }, "webidl/ecmascript-binding/es-exceptions": { diff --git a/test/parallel/parallel.status b/test/parallel/parallel.status index cc99efd7a743d6..8b9a4e80a08031 100644 --- a/test/parallel/parallel.status +++ b/test/parallel/parallel.status @@ -51,6 +51,10 @@ test-esm-loader-hooks-inspect-wait: PASS, FLAKY # https://github.com/nodejs/node/issues/54534 test-runner-run-watch: PASS, FLAKY +[$system==linux && $arch==s390x] +# https://github.com/nodejs/node/issues/58353 +test-http2-debug: PASS, FLAKY + [$system==linux || $system==win32] # https://github.com/nodejs/node/issues/49605 test-runner-watch-mode: PASS,FLAKY @@ -135,6 +139,14 @@ test-tls-client-mindhsize: PASS, FLAKY test-tls-write-error: PASS, FLAKY # https://github.com/nodejs/node/issues/48047 test-http-pipeline-flood: SKIP +# https://github.com/nodejs/node/issues/58582 +test-http-proxy-fetch: PASS, FLAKY +test-https-proxy-fetch: PASS, FLAKY +test-inspector-network-fetch: PASS, FLAKY +test-fetch: PASS, FLAKY +test-without-async-context-frame: PASS, FLAKY +test-process-cpuUsage: PASS, FLAKY + [$asan==on] # https://github.com/nodejs/node/issues/39655 diff --git a/test/parallel/test-assert-typedarray-deepequal.js b/test/parallel/test-assert-typedarray-deepequal.js index b2ed4c698b73b4..371e7161145593 100644 --- a/test/parallel/test-assert-typedarray-deepequal.js +++ b/test/parallel/test-assert-typedarray-deepequal.js @@ -110,15 +110,10 @@ suite('notEqualArrayPairs', () => { makeBlock(assert.deepStrictEqual, arrayPair[0], arrayPair[1]), assert.AssertionError ); - // TODO(puskin94): remove emitWarning override once the partialDeepStrictEqual method is not experimental anymore - // Suppress warnings, necessary otherwise the tools/pseudo-tty.py runner will fail - const originalEmitWarning = process.emitWarning; - process.emitWarning = () => {}; assert.throws( makeBlock(assert.partialDeepStrictEqual, arrayPair[0], arrayPair[1]), assert.AssertionError ); - process.emitWarning = originalEmitWarning; // Restore original process.emitWarning }); } }); diff --git a/test/parallel/test-async-local-storage-isolation.js b/test/parallel/test-async-local-storage-isolation.js new file mode 100644 index 00000000000000..ea87688b6117b2 --- /dev/null +++ b/test/parallel/test-async-local-storage-isolation.js @@ -0,0 +1,67 @@ +'use strict'; +const common = require('../common'); +const { AsyncLocalStorage } = require('node:async_hooks'); +const assert = require('node:assert'); + +// Verify that ALS instances are independent of each other. + +{ + // Verify als2.enterWith() and als2.run inside als1.run() + const als1 = new AsyncLocalStorage(); + const als2 = new AsyncLocalStorage(); + + assert.strictEqual(als1.getStore(), undefined); + assert.strictEqual(als2.getStore(), undefined); + + als1.run('store1', common.mustCall(() => { + assert.strictEqual(als1.getStore(), 'store1'); + assert.strictEqual(als2.getStore(), undefined); + + als2.run('store2', common.mustCall(() => { + assert.strictEqual(als1.getStore(), 'store1'); + assert.strictEqual(als2.getStore(), 'store2'); + })); + assert.strictEqual(als1.getStore(), 'store1'); + assert.strictEqual(als2.getStore(), undefined); + + als2.enterWith('store3'); + assert.strictEqual(als1.getStore(), 'store1'); + assert.strictEqual(als2.getStore(), 'store3'); + })); + + assert.strictEqual(als1.getStore(), undefined); + assert.strictEqual(als2.getStore(), 'store3'); +} + +{ + // Verify als1.disable() has no side effects to als2 and als3 + const als1 = new AsyncLocalStorage(); + const als2 = new AsyncLocalStorage(); + const als3 = new AsyncLocalStorage(); + + als3.enterWith('store3'); + + als1.run('store1', common.mustCall(() => { + assert.strictEqual(als1.getStore(), 'store1'); + assert.strictEqual(als2.getStore(), undefined); + assert.strictEqual(als3.getStore(), 'store3'); + + als2.run('store2', common.mustCall(() => { + assert.strictEqual(als1.getStore(), 'store1'); + assert.strictEqual(als2.getStore(), 'store2'); + assert.strictEqual(als3.getStore(), 'store3'); + + als1.disable(); + assert.strictEqual(als1.getStore(), undefined); + assert.strictEqual(als2.getStore(), 'store2'); + assert.strictEqual(als3.getStore(), 'store3'); + })); + assert.strictEqual(als1.getStore(), undefined); + assert.strictEqual(als2.getStore(), undefined); + assert.strictEqual(als3.getStore(), 'store3'); + })); + + assert.strictEqual(als1.getStore(), undefined); + assert.strictEqual(als2.getStore(), undefined); + assert.strictEqual(als3.getStore(), 'store3'); +} diff --git a/test/parallel/test-binding-constants.js b/test/parallel/test-binding-constants.js index 4a96b7c7443fc6..d57899be50642b 100644 --- a/test/parallel/test-binding-constants.js +++ b/test/parallel/test-binding-constants.js @@ -7,7 +7,7 @@ const constants = internalBinding('constants'); const assert = require('assert'); assert.deepStrictEqual( - Object.keys(constants).sort(), ['crypto', 'fs', 'os', 'trace', 'zlib'] + Object.keys(constants).sort(), ['crypto', 'fs', 'internal', 'os', 'trace', 'zlib'] ); assert.deepStrictEqual( @@ -28,6 +28,6 @@ function test(obj) { } [ - constants, constants.crypto, constants.fs, constants.os, constants.trace, + constants, constants.crypto, constants.fs, constants.internal, constants.os, constants.trace, constants.zlib, constants.os.dlopen, constants.os.errno, constants.os.signals, ].forEach(test); diff --git a/test/parallel/test-buffer-tostring-4gb.js b/test/parallel/test-buffer-tostring-4gb.js new file mode 100644 index 00000000000000..8ab102e559dad9 --- /dev/null +++ b/test/parallel/test-buffer-tostring-4gb.js @@ -0,0 +1,20 @@ +'use strict'; + +// This tests that Buffer.prototype.toString() works with buffers over 4GB. +const common = require('../common'); + +// Must not throw when start and end are within kMaxLength +// Cannot test on 32bit machine as we are testing the case +// when start and end are above the threshold +common.skipIf32Bits(); +const threshold = 0xFFFFFFFF; // 2^32 - 1 +let largeBuffer; +try { + largeBuffer = Buffer.alloc(threshold + 20); +} catch (e) { + if (e.code === 'ERR_MEMORY_ALLOCATION_FAILED' || /Array buffer allocation failed/.test(e.message)) { + common.skip('insufficient space for Buffer.alloc'); + } + throw e; +} +largeBuffer.toString('utf8', threshold, threshold + 20); diff --git a/test/parallel/test-buffer-tostring-range.js b/test/parallel/test-buffer-tostring-range.js index d033cd204b3200..f4adf64c8d9129 100644 --- a/test/parallel/test-buffer-tostring-range.js +++ b/test/parallel/test-buffer-tostring-range.js @@ -1,6 +1,6 @@ 'use strict'; -const common = require('../common'); +require('../common'); const assert = require('assert'); const rangeBuffer = Buffer.from('abc'); @@ -98,11 +98,3 @@ assert.throws(() => { name: 'TypeError', message: 'Unknown encoding: null' }); - -// Must not throw when start and end are within kMaxLength -// Cannot test on 32bit machine as we are testing the case -// when start and end are above the threshold -common.skipIf32Bits(); -const threshold = 0xFFFFFFFF; -const largeBuffer = Buffer.alloc(threshold + 20); -largeBuffer.toString('utf8', threshold, threshold + 20); diff --git a/test/parallel/test-buffer-tostring-rangeerror.js b/test/parallel/test-buffer-tostring-rangeerror.js index 0ebea759b5c42b..52fd3ffa1d4959 100644 --- a/test/parallel/test-buffer-tostring-rangeerror.js +++ b/test/parallel/test-buffer-tostring-rangeerror.js @@ -1,10 +1,15 @@ 'use strict'; -require('../common'); + +const common = require('../common'); // This test ensures that Node.js throws an Error when trying to convert a // large buffer into a string. // Regression test for https://github.com/nodejs/node/issues/649. +if (!common.enoughTestMem) { + common.skip('skipped due to memory requirements'); +} + const assert = require('assert'); const { SlowBuffer, @@ -18,8 +23,22 @@ const message = { code: 'ERR_STRING_TOO_LONG', name: 'Error', }; -assert.throws(() => Buffer(len).toString('utf8'), message); -assert.throws(() => SlowBuffer(len).toString('utf8'), message); -assert.throws(() => Buffer.alloc(len).toString('utf8'), message); -assert.throws(() => Buffer.allocUnsafe(len).toString('utf8'), message); -assert.throws(() => Buffer.allocUnsafeSlow(len).toString('utf8'), message); + +function test(getBuffer) { + let buf; + try { + buf = getBuffer(); + } catch (e) { + // If the buffer allocation fails, we skip the test. + if (e.code === 'ERR_MEMORY_ALLOCATION_FAILED' || /Array buffer allocation failed/.test(e.message)) { + return; + } + } + assert.throws(() => { buf.toString('utf8'); }, message); +} + +test(() => Buffer(len)); +test(() => SlowBuffer(len)); +test(() => Buffer.alloc(len)); +test(() => Buffer.allocUnsafe(len)); +test(() => Buffer.allocUnsafeSlow(len)); diff --git a/test/parallel/test-child-process-spawn-args.js b/test/parallel/test-child-process-spawn-args.js deleted file mode 100644 index ec56f409faf2a9..00000000000000 --- a/test/parallel/test-child-process-spawn-args.js +++ /dev/null @@ -1,55 +0,0 @@ -'use strict'; - -// This test confirms that `undefined`, `null`, and `[]` -// can be used as a placeholder for the second argument (`args`) of `spawn()`. -// Previously, there was a bug where using `undefined` for the second argument -// caused the third argument (`options`) to be ignored. -// See https://github.com/nodejs/node/issues/24912. - -const common = require('../common'); -const tmpdir = require('../common/tmpdir'); - -const assert = require('assert'); -const { spawn } = require('child_process'); - -tmpdir.refresh(); - -const command = common.isWindows ? 'cd' : 'pwd'; -const options = { cwd: tmpdir.path }; - -if (common.isWindows) { - // This test is not the case for Windows based systems - // unless the `shell` options equals to `true` - - options.shell = true; -} - -const testCases = [ - undefined, - null, - [], -]; - -const expectedResult = tmpdir.path.trim().toLowerCase(); - -(async () => { - const results = await Promise.all( - testCases.map((testCase) => { - return new Promise((resolve) => { - const subprocess = spawn(command, testCase, options); - - let accumulatedData = Buffer.alloc(0); - - subprocess.stdout.on('data', common.mustCall((data) => { - accumulatedData = Buffer.concat([accumulatedData, data]); - })); - - subprocess.stdout.on('end', () => { - resolve(accumulatedData.toString().trim().toLowerCase()); - }); - }); - }) - ); - - assert.deepStrictEqual([...new Set(results)], [expectedResult]); -})().then(common.mustCall()); diff --git a/test/parallel/test-child-process-spawn-args.mjs b/test/parallel/test-child-process-spawn-args.mjs new file mode 100644 index 00000000000000..6d0bc9056789dd --- /dev/null +++ b/test/parallel/test-child-process-spawn-args.mjs @@ -0,0 +1,50 @@ +// This test confirms that `undefined`, `null`, and `[]` +// can be used as a placeholder for the second argument (`args`) of `spawn()`. +// Previously, there was a bug where using `undefined` for the second argument +// caused the third argument (`options`) to be ignored. +// See https://github.com/nodejs/node/issues/24912. + +import * as common from '../common/index.mjs'; +import tmpdir from '../common/tmpdir.js'; + +import assert from 'node:assert'; +import { spawn } from 'node:child_process'; +import { once } from 'node:events'; + +tmpdir.refresh(); + +const command = common.isWindows ? 'cd' : 'pwd'; +const options = { cwd: tmpdir.path }; + +if (common.isWindows) { + // This test is not the case for Windows based systems + // unless the `shell` options equals to `true` + options.shell = true; +} + +const testCases = [ + undefined, + null, + [], +]; + +const expectedResult = new Set([tmpdir.path.trim().toLowerCase()]); + +const actualResults = new Set(); + +for (const testCase of testCases) { + const subprocess = spawn(command, testCase, options); + + let accumulatedData = ''; + + subprocess.stdout.setEncoding('utf8'); + subprocess.stdout.on('data', common.mustCall((data) => { + accumulatedData += data; + })); + + await once(subprocess.stdout, 'end'); + + actualResults.add(accumulatedData.trim().toLowerCase()); +} + +assert.deepStrictEqual(actualResults, expectedResult); diff --git a/test/parallel/test-child-process-stdout-flush-exit.js b/test/parallel/test-child-process-stdout-flush-exit.js index 3c5f00d9bb2b13..90f746c39ef6d3 100644 --- a/test/parallel/test-child-process-stdout-flush-exit.js +++ b/test/parallel/test-child-process-stdout-flush-exit.js @@ -25,9 +25,14 @@ const assert = require('assert'); // If child process output to console and exit // The console.log statements here are part of the test. +// Note: This test verifies specific behavior that is *not* guaranteed +// by Node.js's API contract. See https://nodejs.org/api/process.html#processexitcode. +// We are still generally interested in knowing when this test breaks, +// since applications may rely on the implicit behavior of stdout having +// a buffer size up to which they can write data synchronously. if (process.argv[2] === 'child') { console.log('hello'); - for (let i = 0; i < 200; i++) { + for (let i = 0; i < 100; i++) { console.log('filler'); } console.log('goodbye'); diff --git a/test/parallel/test-config-file.js b/test/parallel/test-config-file.js index b2a8625d327549..2b672158a54c35 100644 --- a/test/parallel/test-config-file.js +++ b/test/parallel/test-config-file.js @@ -1,6 +1,7 @@ 'use strict'; -const { spawnPromisified } = require('../common'); +const { spawnPromisified, skipIfSQLiteMissing } = require('../common'); +skipIfSQLiteMissing(); const fixtures = require('../common/fixtures'); const { match, strictEqual } = require('node:assert'); const { test } = require('node:test'); @@ -233,6 +234,30 @@ test('host port flag should be parsed correctly', { skip: !process.features.insp strictEqual(result.code, 0); }); +test('--inspect=true should be parsed correctly', { skip: !process.features.inspector }, async () => { + const result = await spawnPromisified(process.execPath, [ + '--no-warnings', + '--experimental-config-file', + fixtures.path('rc/inspect-true.json'), + '-p', 'require("node:inspector").url()', + ]); + match(result.stderr, /^Debugger listening on (ws:\/\/[^\s]+)/); + match(result.stdout, /ws:\/\/[^\s]+/); + strictEqual(result.code, 0); +}); + +test('--inspect=false should be parsed correctly', { skip: !process.features.inspector }, async () => { + const result = await spawnPromisified(process.execPath, [ + '--no-warnings', + '--experimental-config-file', + fixtures.path('rc/inspect-false.json'), + '-p', 'require("node:inspector").url()', + ]); + strictEqual(result.stderr, ''); + strictEqual(result.stdout, 'undefined\n'); + strictEqual(result.code, 0); +}); + test('no op flag should throw', async () => { const result = await spawnPromisified(process.execPath, [ '--no-warnings', diff --git a/test/parallel/test-crypto-authenticated.js b/test/parallel/test-crypto-authenticated.js index 181ea732b91281..5f74f7c2611138 100644 --- a/test/parallel/test-crypto-authenticated.js +++ b/test/parallel/test-crypto-authenticated.js @@ -18,7 +18,7 @@ // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // USE OR OTHER DEALINGS IN THE SOFTWARE. -// Flags: --no-warnings + 'use strict'; const common = require('../common'); if (!common.hasCrypto) { @@ -245,7 +245,7 @@ for (const test of TEST_CASES) { assert.strictEqual(text.toString('utf8'), 'node'); } -// Test that create(De|C)ipher(iv)? throws if the mode is CCM and an invalid +// Test that create(De|C)ipheriv throws if the mode is CCM and an invalid // authentication tag length has been specified. { for (const authTagLength of [-1, true, false, NaN, 5.5]) { @@ -303,8 +303,8 @@ for (const test of TEST_CASES) { } } -// Test that create(De|C)ipher(iv)? throws if the mode is CCM or OCB and no -// authentication tag has been specified. +// Test that create(De|C)ipheriv throws if the mode is CCM or OCB and no +// authentication tag length has been specified. { for (const mode of ['ccm', 'ocb']) { assert.throws(() => { @@ -315,8 +315,8 @@ for (const test of TEST_CASES) { message: `authTagLength required for aes-256-${mode}` }); - // CCM decryption and create(De|C)ipher are unsupported in FIPS mode. - if (!isFipsEnabled) { + // CCM decryption is unsupported in FIPS mode. + if (!isFipsEnabled || mode !== 'ccm') { assert.throws(() => { crypto.createDecipheriv(`aes-256-${mode}`, 'FxLKsqdmv0E9xrQhp0b1ZgI0K7JFZJM8', @@ -448,34 +448,65 @@ for (const test of TEST_CASES) { } // Test that the authentication tag can be set at any point before calling -// final() in GCM or OCB mode. +// final() in GCM mode, OCB mode, and for ChaCha20-Poly1305. { + const aad = Buffer.from('Shared', 'utf8'); const plain = Buffer.from('Hello world', 'utf8'); - const key = Buffer.from('0123456789abcdef', 'utf8'); + const key = Buffer.from('0123456789abcdefghijklmnopqrstuv', 'utf8'); const iv = Buffer.from('0123456789ab', 'utf8'); - for (const mode of ['gcm', 'ocb']) { - for (const authTagLength of mode === 'gcm' ? [undefined, 8] : [8]) { - const cipher = crypto.createCipheriv(`aes-128-${mode}`, key, iv, { + function testAllOrders({ alg, authTagLength, useAAD, useMessage }) { + // Encrypt the message first to obtain ciphertext and authTag. + const cipher = crypto.createCipheriv(alg, key, iv, { + authTagLength + }); + if (useAAD) { + cipher.setAAD(aad); + } + const ciphertext = useMessage ? Buffer.concat([cipher.update(plain), cipher.final()]) : cipher.final(); + const authTag = cipher.getAuthTag(); + assert.strictEqual(authTag.length, authTagLength ?? 16); + + // Test decryption with each possible order of operations. + for (const authTagTime of ['beforeAAD', 'beforeUpdate', 'afterUpdate']) { + const decipher = crypto.createDecipheriv(alg, key, iv, { authTagLength }); - const ciphertext = Buffer.concat([cipher.update(plain), cipher.final()]); - const authTag = cipher.getAuthTag(); + if (authTagTime === 'beforeAAD') { + decipher.setAuthTag(authTag); + } + if (useAAD) { + decipher.setAAD(aad); + } + if (authTagTime === 'beforeUpdate') { + decipher.setAuthTag(authTag); + } + const resultBuffers = []; + if (useMessage) { + resultBuffers.push(decipher.update(ciphertext)); + } + if (authTagTime === 'afterUpdate') { + decipher.setAuthTag(authTag); + } + resultBuffers.push(decipher.final()); + const result = Buffer.concat(resultBuffers); + if (useMessage) { + assert.deepStrictEqual(result, plain); + } else { + assert.strictEqual(result.length, 0); + } + } + } - for (const authTagBeforeUpdate of [true, false]) { - const decipher = crypto.createDecipheriv(`aes-128-${mode}`, key, iv, { - authTagLength - }); - if (authTagBeforeUpdate) { - decipher.setAuthTag(authTag); - } - const resultUpdate = decipher.update(ciphertext); - if (!authTagBeforeUpdate) { - decipher.setAuthTag(authTag); - } - const resultFinal = decipher.final(); - const result = Buffer.concat([resultUpdate, resultFinal]); - assert(result.equals(plain)); + for (const alg of ['aes-256-gcm', 'aes-256-ocb', 'chacha20-poly1305']) { + for (const authTagLength of alg === 'aes-256-gcm' ? [undefined, 8] : [8]) { + for (const [useAAD, useMessage] of [ + [false, false], // No AAD, no update. + [true, false], // Only AAD (e.g., GMAC). + [false, true], // No AAD, only message. + [true, true], // Both AAD and message. + ]) { + testAllOrders({ alg, authTagLength, useAAD, useMessage }); } } } @@ -561,17 +592,14 @@ for (const test of TEST_CASES) { const iv = Buffer.alloc(12); const opts = { authTagLength: 10 }; - for (const cipher of [ - crypto.createCipheriv(algo, key, iv, opts), - ]) { - assert.throws(() => { - cipher.final(); - }, hasOpenSSL3 ? { - code: 'ERR_OSSL_TAG_NOT_SET' - } : { - message: /Unsupported state/ - }); - } + const cipher = crypto.createCipheriv(algo, key, iv, opts); + assert.throws(() => { + cipher.final(); + }, hasOpenSSL3 ? { + code: 'ERR_OSSL_TAG_NOT_SET' + } : { + message: /Unsupported state/ + }); } { diff --git a/test/parallel/test-crypto-fips.js b/test/parallel/test-crypto-fips.js index de004b9a9e8f23..a5e25b8fd1073a 100644 --- a/test/parallel/test-crypto-fips.js +++ b/test/parallel/test-crypto-fips.js @@ -23,13 +23,16 @@ const FIPS_ENABLE_ERROR_STRING = 'OpenSSL error when trying to enable FIPS:'; const CNF_FIPS_ON = fixtures.path('openssl_fips_enabled.cnf'); const CNF_FIPS_OFF = fixtures.path('openssl_fips_disabled.cnf'); +const kNoFailure = 0; +const kGenericUserError = 1; + let num_children_ok = 0; function sharedOpenSSL() { return process.config.variables.node_shared_openssl; } -function testHelper(stream, args, expectedOutput, cmd, env) { +function testHelper(stream, args, expectedStatus, expectedOutput, cmd, env) { const fullArgs = args.concat(['-e', `console.log(${cmd})`]); const child = spawnSync(process.execPath, fullArgs, { cwd: path.dirname(process.execPath), @@ -56,6 +59,7 @@ function testHelper(stream, args, expectedOutput, cmd, env) { // Normal path where we expect either FIPS enabled or disabled. assert.strictEqual(getFipsValue, expectedOutput); } + assert.strictEqual(child.status, expectedStatus); childOk(child); } @@ -66,6 +70,7 @@ function testHelper(stream, args, expectedOutput, cmd, env) { testHelper( testFipsCrypto() ? 'stdout' : 'stderr', ['--enable-fips'], + testFipsCrypto() ? kNoFailure : kGenericUserError, testFipsCrypto() ? FIPS_ENABLED : FIPS_ENABLE_ERROR_STRING, 'process.versions', process.env); @@ -74,6 +79,7 @@ testHelper( testHelper( testFipsCrypto() ? 'stdout' : 'stderr', ['--force-fips'], + testFipsCrypto() ? kNoFailure : kGenericUserError, testFipsCrypto() ? FIPS_ENABLED : FIPS_ENABLE_ERROR_STRING, 'process.versions', process.env); @@ -85,6 +91,7 @@ if (!sharedOpenSSL()) { testHelper( 'stdout', [], + kNoFailure, FIPS_DISABLED, 'require("crypto").getFips()', { ...process.env, 'OPENSSL_CONF': ' ' }); @@ -94,6 +101,7 @@ if (!sharedOpenSSL()) { testHelper( 'stderr', [], + kGenericUserError, 'Calling crypto.setFips() is not supported in workers', 'new worker_threads.Worker(\'require("crypto").setFips(true);\', { eval: true })', process.env); @@ -120,6 +128,7 @@ if (!sharedOpenSSL() && !hasOpenSSL3) { testHelper( 'stdout', [`--openssl-config=${CNF_FIPS_ON}`], + kNoFailure, testFipsCrypto() ? FIPS_ENABLED : FIPS_DISABLED, 'require("crypto").getFips()', process.env); @@ -128,6 +137,7 @@ if (!sharedOpenSSL() && !hasOpenSSL3) { testHelper( 'stdout', [], + kNoFailure, testFipsCrypto() ? FIPS_ENABLED : FIPS_DISABLED, 'require("crypto").getFips()', Object.assign({}, process.env, { 'OPENSSL_CONF': CNF_FIPS_ON })); @@ -136,6 +146,7 @@ if (!sharedOpenSSL() && !hasOpenSSL3) { testHelper( 'stdout', [`--openssl-config=${CNF_FIPS_ON}`], + kNoFailure, testFipsCrypto() ? FIPS_ENABLED : FIPS_DISABLED, 'require("crypto").getFips()', Object.assign({}, process.env, { 'OPENSSL_CONF': CNF_FIPS_OFF })); @@ -149,6 +160,7 @@ if (!hasOpenSSL3) { testHelper( 'stdout', [`--openssl-config=${CNF_FIPS_OFF}`], + kNoFailure, FIPS_DISABLED, 'require("crypto").getFips()', Object.assign({}, process.env, { 'OPENSSL_CONF': CNF_FIPS_ON })); @@ -157,6 +169,7 @@ if (!hasOpenSSL3) { testHelper( testFipsCrypto() ? 'stdout' : 'stderr', ['--enable-fips', `--openssl-config=${CNF_FIPS_OFF}`], + testFipsCrypto() ? kNoFailure : kGenericUserError, testFipsCrypto() ? FIPS_ENABLED : FIPS_UNSUPPORTED_ERROR_STRING, 'require("crypto").getFips()', process.env); @@ -164,6 +177,7 @@ if (!hasOpenSSL3) { testHelper( testFipsCrypto() ? 'stdout' : 'stderr', ['--force-fips', `--openssl-config=${CNF_FIPS_OFF}`], + testFipsCrypto() ? kNoFailure : kGenericUserError, testFipsCrypto() ? FIPS_ENABLED : FIPS_UNSUPPORTED_ERROR_STRING, 'require("crypto").getFips()', process.env); @@ -171,6 +185,7 @@ if (!hasOpenSSL3) { testHelper( testFipsCrypto() ? 'stdout' : 'stderr', ['--enable-fips'], + testFipsCrypto() ? kNoFailure : kGenericUserError, testFipsCrypto() ? FIPS_ENABLED : FIPS_UNSUPPORTED_ERROR_STRING, 'require("crypto").getFips()', process.env); @@ -179,6 +194,7 @@ if (!hasOpenSSL3) { testHelper( testFipsCrypto() ? 'stdout' : 'stderr', ['--force-fips'], + testFipsCrypto() ? kNoFailure : kGenericUserError, testFipsCrypto() ? FIPS_ENABLED : FIPS_UNSUPPORTED_ERROR_STRING, 'require("crypto").getFips()', process.env); @@ -187,6 +203,7 @@ if (!hasOpenSSL3) { testHelper( testFipsCrypto() ? 'stdout' : 'stderr', ['--enable-fips'], + testFipsCrypto() ? kNoFailure : kGenericUserError, testFipsCrypto() ? FIPS_ENABLED : FIPS_UNSUPPORTED_ERROR_STRING, 'require("crypto").getFips()', Object.assign({}, process.env, { 'OPENSSL_CONF': CNF_FIPS_OFF })); @@ -195,6 +212,7 @@ if (!hasOpenSSL3) { testHelper( testFipsCrypto() ? 'stdout' : 'stderr', ['--force-fips'], + testFipsCrypto() ? kNoFailure : kGenericUserError, testFipsCrypto() ? FIPS_ENABLED : FIPS_UNSUPPORTED_ERROR_STRING, 'require("crypto").getFips()', Object.assign({}, process.env, { 'OPENSSL_CONF': CNF_FIPS_OFF })); @@ -203,6 +221,7 @@ if (!hasOpenSSL3) { testHelper( testFipsCrypto() ? 'stdout' : 'stderr', [], + testFipsCrypto() ? kNoFailure : kGenericUserError, testFipsCrypto() ? FIPS_ENABLED : FIPS_UNSUPPORTED_ERROR_STRING, '(require("crypto").setFips(true),' + 'require("crypto").getFips())', @@ -212,6 +231,7 @@ if (!hasOpenSSL3) { testHelper( testFipsCrypto() ? 'stdout' : 'stderr', [], + testFipsCrypto() ? kNoFailure : kGenericUserError, testFipsCrypto() ? FIPS_DISABLED : FIPS_UNSUPPORTED_ERROR_STRING, '(require("crypto").setFips(true),' + 'require("crypto").setFips(false),' + @@ -222,6 +242,7 @@ if (!hasOpenSSL3) { testHelper( testFipsCrypto() ? 'stdout' : 'stderr', [`--openssl-config=${CNF_FIPS_OFF}`], + testFipsCrypto() ? kNoFailure : kGenericUserError, testFipsCrypto() ? FIPS_ENABLED : FIPS_UNSUPPORTED_ERROR_STRING, '(require("crypto").setFips(true),' + 'require("crypto").getFips())', @@ -231,6 +252,7 @@ if (!hasOpenSSL3) { testHelper( 'stdout', [`--openssl-config=${CNF_FIPS_ON}`], + kNoFailure, FIPS_DISABLED, '(require("crypto").setFips(false),' + 'require("crypto").getFips())', @@ -240,6 +262,7 @@ if (!hasOpenSSL3) { testHelper( testFipsCrypto() ? 'stdout' : 'stderr', ['--enable-fips'], + testFipsCrypto() ? kNoFailure : kGenericUserError, testFipsCrypto() ? FIPS_DISABLED : FIPS_UNSUPPORTED_ERROR_STRING, '(require("crypto").setFips(false),' + 'require("crypto").getFips())', @@ -249,6 +272,7 @@ if (!hasOpenSSL3) { testHelper( 'stderr', ['--force-fips'], + kGenericUserError, testFipsCrypto() ? FIPS_ERROR_STRING2 : FIPS_UNSUPPORTED_ERROR_STRING, 'require("crypto").setFips(false)', process.env); @@ -257,6 +281,7 @@ if (!hasOpenSSL3) { testHelper( testFipsCrypto() ? 'stdout' : 'stderr', ['--force-fips'], + testFipsCrypto() ? kNoFailure : kGenericUserError, testFipsCrypto() ? FIPS_ENABLED : FIPS_UNSUPPORTED_ERROR_STRING, '(require("crypto").setFips(true),' + 'require("crypto").getFips())', @@ -266,6 +291,7 @@ if (!hasOpenSSL3) { testHelper( 'stderr', ['--force-fips', '--enable-fips'], + kGenericUserError, testFipsCrypto() ? FIPS_ERROR_STRING2 : FIPS_UNSUPPORTED_ERROR_STRING, 'require("crypto").setFips(false)', process.env); @@ -274,6 +300,7 @@ if (!hasOpenSSL3) { testHelper( 'stderr', ['--enable-fips', '--force-fips'], + kGenericUserError, testFipsCrypto() ? FIPS_ERROR_STRING2 : FIPS_UNSUPPORTED_ERROR_STRING, 'require("crypto").setFips(false)', process.env); diff --git a/test/parallel/test-crypto-getcipherinfo.js b/test/parallel/test-crypto-getcipherinfo.js index 64b79fc36ccf4d..b0902908b5c454 100644 --- a/test/parallel/test-crypto-getcipherinfo.js +++ b/test/parallel/test-crypto-getcipherinfo.js @@ -62,9 +62,13 @@ assert(getCipherInfo('aes-128-cbc', { ivLength: 16 })); assert(!getCipherInfo('aes-128-ccm', { ivLength: 1 })); assert(!getCipherInfo('aes-128-ccm', { ivLength: 14 })); -for (let n = 7; n <= 13; n++) - assert(getCipherInfo('aes-128-ccm', { ivLength: n })); +if (!process.features.openssl_is_boringssl) { + for (let n = 7; n <= 13; n++) + assert(getCipherInfo('aes-128-ccm', { ivLength: n })); +} assert(!getCipherInfo('aes-128-ocb', { ivLength: 16 })); -for (let n = 1; n < 16; n++) - assert(getCipherInfo('aes-128-ocb', { ivLength: n })); +if (!process.features.openssl_is_boringssl) { + for (let n = 1; n < 16; n++) + assert(getCipherInfo('aes-128-ocb', { ivLength: n })); +} diff --git a/test/parallel/test-crypto-hkdf.js b/test/parallel/test-crypto-hkdf.js index 3f7e61e9b2ebc0..360ed52370fbe1 100644 --- a/test/parallel/test-crypto-hkdf.js +++ b/test/parallel/test-crypto-hkdf.js @@ -125,7 +125,7 @@ const algorithms = [ ['sha256', '', 'salt', '', 10], ['sha512', 'secret', 'salt', '', 15], ]; -if (!hasOpenSSL3) +if (!hasOpenSSL3 && !process.features.openssl_is_boringssl) algorithms.push(['whirlpool', 'secret', '', 'info', 20]); algorithms.forEach(([ hash, secret, salt, info, length ]) => { diff --git a/test/parallel/test-crypto-stream.js b/test/parallel/test-crypto-stream.js index 62be4eaf6edfb0..747af780469c22 100644 --- a/test/parallel/test-crypto-stream.js +++ b/test/parallel/test-crypto-stream.js @@ -74,14 +74,14 @@ const decipher = crypto.createDecipheriv('aes-128-cbc', badkey, iv); cipher.pipe(decipher) .on('error', common.expectsError(hasOpenSSL3 ? { - message: /bad decrypt/, + message: /bad[\s_]decrypt/, library: 'Provider routines', - reason: 'bad decrypt', + reason: /bad[\s_]decrypt/i, } : { - message: /bad decrypt/, + message: /bad[\s_]decrypt/i, function: 'EVP_DecryptFinal_ex', library: 'digital envelope routines', - reason: 'bad decrypt', + reason: /bad[\s_]decrypt/i, })); cipher.end('Papaya!'); // Should not cause an unhandled exception. diff --git a/test/parallel/test-crypto-x509.js b/test/parallel/test-crypto-x509.js index f75e1d63470bfb..4e32222ceed17f 100644 --- a/test/parallel/test-crypto-x509.js +++ b/test/parallel/test-crypto-x509.js @@ -97,8 +97,6 @@ const der = Buffer.from( assert.strictEqual(x509.infoAccess, infoAccessCheck); assert.strictEqual(x509.validFrom, 'Sep 3 21:40:37 2022 GMT'); assert.strictEqual(x509.validTo, 'Jun 17 21:40:37 2296 GMT'); - assert.deepStrictEqual(x509.validFromDate, new Date('2022-09-03T21:40:37Z')); - assert.deepStrictEqual(x509.validToDate, new Date('2296-06-17T21:40:37Z')); assert.strictEqual( x509.fingerprint, '8B:89:16:C4:99:87:D2:13:1A:64:94:36:38:A5:32:01:F0:95:3B:53'); @@ -118,6 +116,11 @@ const der = Buffer.from( assert.deepStrictEqual(x509.raw, der); + if (!process.features.openssl_is_boringssl) { + assert.deepStrictEqual(x509.validFromDate, new Date('2022-09-03T21:40:37Z')); + assert.deepStrictEqual(x509.validToDate, new Date('2296-06-17T21:40:37Z')); + } + assert(x509.publicKey); assert.strictEqual(x509.publicKey.type, 'public'); @@ -356,13 +359,15 @@ tAt3hIKFD1bJt6c6WtMH2Su3syosWxmdmGk5ihslB00lvLpfj/wed8i3bkcB1doq UcXd/5qu2GhokrKU2cPttU+XAN2Om6a0 -----END CERTIFICATE-----`; - const cert = new X509Certificate(certPem); - assert.throws(() => cert.publicKey, { - message: hasOpenSSL3 ? /decode error/ : /wrong tag/, - name: 'Error' - }); + if (!process.features.openssl_is_boringssl) { + const cert = new X509Certificate(certPem); + assert.throws(() => cert.publicKey, { + message: hasOpenSSL3 ? /decode error/ : /wrong tag/, + name: 'Error' + }); - assert.strictEqual(cert.checkIssued(cert), false); + assert.strictEqual(cert.checkIssued(cert), false); + } } { @@ -401,8 +406,10 @@ UidvpWWipVLZgK+oDks+bKTobcoXGW9oXobiIYqslXPy -----END CERTIFICATE-----`.trim(); const c1 = new X509Certificate(certPemUTCTime); - assert.deepStrictEqual(c1.validFromDate, new Date('1949-12-25T23:59:58Z')); - assert.deepStrictEqual(c1.validToDate, new Date('1950-01-01T23:59:58Z')); + if (!process.features.openssl_is_boringssl) { + assert.deepStrictEqual(c1.validFromDate, new Date('1949-12-25T23:59:58Z')); + assert.deepStrictEqual(c1.validToDate, new Date('1950-01-01T23:59:58Z')); + } // The GeneralizedTime format is used for dates in 2050 or later. const certPemGeneralizedTime = `-----BEGIN CERTIFICATE----- @@ -436,6 +443,8 @@ CWwQO8JZjJqFtqtuzy2n+gLCvqePgG/gmSqHOPm2ZbLW -----END CERTIFICATE-----`.trim(); const c2 = new X509Certificate(certPemGeneralizedTime); - assert.deepStrictEqual(c2.validFromDate, new Date('2049-12-26T00:00:01Z')); - assert.deepStrictEqual(c2.validToDate, new Date('2050-01-02T00:00:01Z')); + if (!process.features.openssl_is_boringssl) { + assert.deepStrictEqual(c2.validFromDate, new Date('2049-12-26T00:00:01Z')); + assert.deepStrictEqual(c2.validToDate, new Date('2050-01-02T00:00:01Z')); + } } diff --git a/test/parallel/test-crypto.js b/test/parallel/test-crypto.js index 93644e016de447..84111740cd9ef6 100644 --- a/test/parallel/test-crypto.js +++ b/test/parallel/test-crypto.js @@ -218,9 +218,9 @@ assert.throws(() => { } : { name: 'Error', message: /routines:RSA_sign:digest too big for rsa key$/, - library: 'rsa routines', + library: /rsa routines/i, function: 'RSA_sign', - reason: 'digest too big for rsa key', + reason: /digest[\s_]too[\s_]big[\s_]for[\s_]rsa[\s_]key/i, code: 'ERR_OSSL_RSA_DIGEST_TOO_BIG_FOR_RSA_KEY' }); return true; diff --git a/test/parallel/test-diagnostics-channel-http2-client-stream-close-error.js b/test/parallel/test-diagnostics-channel-http2-client-stream-close-error.js new file mode 100644 index 00000000000000..b7b201eeaf3874 --- /dev/null +++ b/test/parallel/test-diagnostics-channel-http2-client-stream-close-error.js @@ -0,0 +1,44 @@ +'use strict'; + +const common = require('../common'); +if (!common.hasCrypto) + common.skip('missing crypto'); + +// This test ensures that the built-in HTTP/2 diagnostics channels are reporting +// the diagnostics messages for the 'http2.client.stream.close' channel when +// a ClientHttp2Stream is destroyed because of an error. + +const assert = require('assert'); +const dc = require('diagnostics_channel'); +const http2 = require('http2'); +const { Duplex } = require('stream'); + +dc.subscribe('http2.client.stream.close', common.mustCall(({ stream }) => { + // Since ClientHttp2Stream is not exported from any module, this just checks + // if the stream is an instance of Duplex and the constructor name is + // 'ClientHttp2Stream'. + assert.ok(stream instanceof Duplex); + assert.strictEqual(stream.constructor.name, 'ClientHttp2Stream'); + assert.strictEqual(stream.closed, true); + assert.strictEqual(stream.destroyed, true); + + assert.strictEqual(stream.rstCode, http2.constants.NGHTTP2_CANCEL); +})); + +const server = http2.createServer(); +server.listen(0, common.mustCall(() => { + const port = server.address().port; + const client = http2.connect(`http://localhost:${port}`); + + const ac = new AbortController(); + const stream = client.request({}, { signal: ac.signal }); + ac.abort(); + + stream.on('error', common.mustCall((err) => { + assert.strictEqual(err.code, 'ABORT_ERR'); + assert.strictEqual(err.name, 'AbortError'); + + client.close(); + server.close(); + })); +})); diff --git a/test/parallel/test-diagnostics-channel-http2-client-stream-close.js b/test/parallel/test-diagnostics-channel-http2-client-stream-close.js new file mode 100644 index 00000000000000..72fbe91195c7f4 --- /dev/null +++ b/test/parallel/test-diagnostics-channel-http2-client-stream-close.js @@ -0,0 +1,63 @@ +'use strict'; + +const common = require('../common'); +if (!common.hasCrypto) + common.skip('missing crypto'); + +// This test ensures that the built-in HTTP/2 diagnostics channels are reporting +// the diagnostics messages for the 'http2.client.stream.close' channel when +// ClientHttp2Streams created by these actions are closed: +// - the client calling ClientHttp2Session#request() +// - in response to an incoming 'push' event from the server + +const Countdown = require('../common/countdown'); +const assert = require('assert'); +const dc = require('diagnostics_channel'); +const http2 = require('http2'); +const { Duplex } = require('stream'); + +const clientHttp2StreamCloseCount = 2; + +dc.subscribe('http2.client.stream.close', common.mustCall(({ stream }) => { + // Since ClientHttp2Stream is not exported from any module, this just checks + // if the stream is an instance of Duplex and the constructor name is + // 'ClientHttp2Stream'. + assert.ok(stream instanceof Duplex); + assert.strictEqual(stream.constructor.name, 'ClientHttp2Stream'); + assert.strictEqual(stream.closed, true); + assert.strictEqual(stream.destroyed, false); + + assert.strictEqual(stream.rstCode, http2.constants.NGHTTP2_NO_ERROR); +}, clientHttp2StreamCloseCount)); + +const server = http2.createServer(); +server.on('stream', common.mustCall((stream) => { + stream.respond(); + stream.end(); + + stream.pushStream({}, common.mustSucceed((pushStream) => { + pushStream.respond(); + pushStream.end(); + })); +})); + +server.listen(0, common.mustCall(() => { + const port = server.address().port; + const client = http2.connect(`http://localhost:${port}`); + + const countdown = new Countdown(clientHttp2StreamCloseCount, () => { + client.close(); + server.close(); + }); + + const stream = client.request({}); + stream.on('response', common.mustCall(() => { + countdown.dec(); + })); + + client.on('stream', common.mustCall((pushStream) => { + pushStream.on('push', common.mustCall(() => { + countdown.dec(); + })); + })); +})); diff --git a/test/parallel/test-diagnostics-channel-http2-client-stream-created.js b/test/parallel/test-diagnostics-channel-http2-client-stream-created.js new file mode 100644 index 00000000000000..75806db591438e --- /dev/null +++ b/test/parallel/test-diagnostics-channel-http2-client-stream-created.js @@ -0,0 +1,60 @@ +'use strict'; + +const common = require('../common'); +if (!common.hasCrypto) + common.skip('missing crypto'); + +// This test ensures that the built-in HTTP/2 diagnostics channels are reporting +// the diagnostics messages for the 'http2.client.stream.created' channel when +// ClientHttp2Streams are created by both: +// - the client calling ClientHttp2Session#request() +// - in response to an incoming 'push' event from the server + +const Countdown = require('../common/countdown'); +const assert = require('assert'); +const dc = require('diagnostics_channel'); +const http2 = require('http2'); +const { Duplex } = require('stream'); + +const clientHttp2StreamCreationCount = 2; + +dc.subscribe('http2.client.stream.created', common.mustCall(({ stream, headers }) => { + // Since ClientHttp2Stream is not exported from any module, this just checks + // if the stream is an instance of Duplex and the constructor name is + // 'ClientHttp2Stream'. + assert.ok(stream instanceof Duplex); + assert.strictEqual(stream.constructor.name, 'ClientHttp2Stream'); + assert.ok(headers && !Array.isArray(headers) && typeof headers === 'object'); +}, clientHttp2StreamCreationCount)); + +const server = http2.createServer(); +server.on('stream', common.mustCall((stream) => { + stream.respond(); + stream.end(); + + stream.pushStream({}, common.mustSucceed((pushStream) => { + pushStream.respond(); + pushStream.end(); + }, 1)); +}, 1)); + +server.listen(0, common.mustCall(() => { + const port = server.address().port; + const client = http2.connect(`http://localhost:${port}`); + + const countdown = new Countdown(clientHttp2StreamCreationCount, () => { + client.close(); + server.close(); + }); + + const stream = client.request({}); + stream.on('response', common.mustCall(() => { + countdown.dec(); + })); + + client.on('stream', common.mustCall((pushStream) => { + pushStream.on('push', common.mustCall(() => { + countdown.dec(); + }, 1)); + }, 1)); +}, 1)); diff --git a/test/parallel/test-diagnostics-channel-http2-client-stream-error.js b/test/parallel/test-diagnostics-channel-http2-client-stream-error.js new file mode 100644 index 00000000000000..14e745c0b305c2 --- /dev/null +++ b/test/parallel/test-diagnostics-channel-http2-client-stream-error.js @@ -0,0 +1,46 @@ +'use strict'; + +const common = require('../common'); +if (!common.hasCrypto) + common.skip('missing crypto'); + +// This test ensures that the built-in HTTP/2 diagnostics channels are reporting +// the diagnostics messages for the 'http2.client.stream.error' channel when +// an error occurs during the processing of a ClientHttp2Stream. + +const assert = require('assert'); +const dc = require('diagnostics_channel'); +const http2 = require('http2'); +const { Duplex } = require('stream'); + +dc.subscribe('http2.client.stream.error', common.mustCall(({ stream, error }) => { + // Since ClientHttp2Stream is not exported from any module, this just checks + // if the stream is an instance of Duplex and the constructor name is + // 'ClientHttp2Stream'. + assert.ok(stream instanceof Duplex); + assert.strictEqual(stream.constructor.name, 'ClientHttp2Stream'); + assert.strictEqual(stream.closed, true); + assert.strictEqual(stream.destroyed, true); + + assert.ok(error); + assert.strictEqual(error.code, 'ABORT_ERR'); + assert.strictEqual(error.name, 'AbortError'); +})); + +const server = http2.createServer(); +server.listen(0, common.mustCall(() => { + const port = server.address().port; + const client = http2.connect(`http://localhost:${port}`); + + const ac = new AbortController(); + const stream = client.request({}, { signal: ac.signal }); + ac.abort(); + + stream.on('error', common.mustCall((err) => { + assert.strictEqual(err.code, 'ABORT_ERR'); + assert.strictEqual(err.name, 'AbortError'); + + client.close(); + server.close(); + })); +})); diff --git a/test/parallel/test-diagnostics-channel-http2-client-stream-finish.js b/test/parallel/test-diagnostics-channel-http2-client-stream-finish.js new file mode 100644 index 00000000000000..c8b26471e28209 --- /dev/null +++ b/test/parallel/test-diagnostics-channel-http2-client-stream-finish.js @@ -0,0 +1,63 @@ +'use strict'; + +const common = require('../common'); +if (!common.hasCrypto) + common.skip('missing crypto'); + +// This test ensures that the built-in HTTP/2 diagnostics channels are reporting +// the diagnostics messages for the 'http2.client.stream.finish' channel when +// ClientHttp2Streams are received by both: +// - the 'response' event +// - the 'push' event + +const Countdown = require('../common/countdown'); +const assert = require('assert'); +const dc = require('diagnostics_channel'); +const http2 = require('http2'); +const { Duplex } = require('stream'); + +const clientHttp2StreamFinishCount = 2; + +dc.subscribe('http2.client.stream.finish', common.mustCall(({ stream, headers, flags }) => { + // Since ClientHttp2Stream is not exported from any module, this just checks + // if the stream is an instance of Duplex and the constructor name is + // 'ClientHttp2Stream'. + assert.ok(stream instanceof Duplex); + assert.strictEqual(stream.constructor.name, 'ClientHttp2Stream'); + + assert.ok(headers && !Array.isArray(headers) && typeof headers === 'object'); + + assert.strictEqual(typeof flags, 'number'); +}, clientHttp2StreamFinishCount)); + +const server = http2.createServer(); +server.on('stream', common.mustCall((stream) => { + stream.respond(); + stream.end(); + + stream.pushStream({}, common.mustSucceed((pushStream) => { + pushStream.respond(); + pushStream.end(); + })); +})); + +server.listen(0, common.mustCall(() => { + const port = server.address().port; + const client = http2.connect(`http://localhost:${port}`); + + const countdown = new Countdown(clientHttp2StreamFinishCount, () => { + client.close(); + server.close(); + }); + + const stream = client.request({}); + stream.on('response', common.mustCall(() => { + countdown.dec(); + })); + + client.on('stream', common.mustCall((pushStream) => { + pushStream.on('push', common.mustCall(() => { + countdown.dec(); + })); + })); +})); diff --git a/test/parallel/test-diagnostics-channel-http2-client-stream-start.js b/test/parallel/test-diagnostics-channel-http2-client-stream-start.js new file mode 100644 index 00000000000000..e8edf3a0a49f4a --- /dev/null +++ b/test/parallel/test-diagnostics-channel-http2-client-stream-start.js @@ -0,0 +1,59 @@ +'use strict'; + +const common = require('../common'); +if (!common.hasCrypto) + common.skip('missing crypto'); + +// This test ensures that the built-in HTTP/2 diagnostics channels are reporting +// the diagnostics messages for the 'http2.client.stream.start' channel when +// ClientHttp2Streams are started by both: +// - the client calling ClientHttp2Session#request() +// - in response to an incoming 'push' event from the server + +const Countdown = require('../common/countdown'); +const assert = require('assert'); +const dc = require('diagnostics_channel'); +const http2 = require('http2'); +const { Duplex } = require('stream'); + +const clientHttp2StreamStartCount = 2; + +dc.subscribe('http2.client.stream.start', common.mustCall(({ stream, headers }) => { + // Since ClientHttp2Stream is not exported from any module, this just checks + // if the stream is an instance of Duplex. + assert.ok(stream instanceof Duplex); + assert.strictEqual(stream.constructor.name, 'ClientHttp2Stream'); + assert.ok(headers && !Array.isArray(headers) && typeof headers === 'object'); +}, clientHttp2StreamStartCount)); + +const server = http2.createServer(); +server.on('stream', common.mustCall((stream) => { + stream.respond(); + stream.end(); + + stream.pushStream({}, common.mustSucceed((pushStream) => { + pushStream.respond(); + pushStream.end(); + }, 1)); +}, 1)); + +server.listen(0, common.mustCall(() => { + const port = server.address().port; + const client = http2.connect(`http://localhost:${port}`); + + const countdown = new Countdown(clientHttp2StreamStartCount, () => { + client.close(); + server.close(); + }); + + const stream = client.request({}); + stream.on('response', common.mustCall(() => { + countdown.dec(); + })); + + client.on('stream', common.mustCall((pushStream) => { + pushStream.on('push', common.mustCall(() => { + countdown.dec(); + }, 1)); + }, 1)); +}, 1)); diff --git a/test/parallel/test-diagnostics-channel-http2-server-stream-created-start-timing.js b/test/parallel/test-diagnostics-channel-http2-server-stream-created-start-timing.js new file mode 100644 index 00000000000000..976e2fb3f2eceb --- /dev/null +++ b/test/parallel/test-diagnostics-channel-http2-server-stream-created-start-timing.js @@ -0,0 +1,65 @@ +'use strict'; + +const common = require('../common'); +if (!common.hasCrypto) + common.skip('missing crypto'); + +// This test ensures that the built-in HTTP/2 diagnostics channels are reporting +// the diagnostics messages for the 'http2.server.stream.start' channel only +// after the 'http2.server.stream.created' channel. + +const Countdown = require('../common/countdown'); +const assert = require('assert'); +const dc = require('diagnostics_channel'); +const http2 = require('http2'); + +const serverHttp2StreamCreationCount = 2; + +const map = {}; + +dc.subscribe('http2.server.stream.created', common.mustCall(({ stream, headers }) => { + map[stream.id] = { ...map[stream.id], 'createdTime': process.hrtime.bigint() }; +}, serverHttp2StreamCreationCount)); + +dc.subscribe('http2.server.stream.start', common.mustCall(({ stream, headers }) => { + map[stream.id] = { ...map[stream.id], 'startTime': process.hrtime.bigint() }; +}, serverHttp2StreamCreationCount)); + +const server = http2.createServer(); +server.on('stream', common.mustCall((stream) => { + stream.respond(); + stream.end(); + + stream.pushStream({}, common.mustSucceed((pushStream) => { + pushStream.respond(); + pushStream.end(); + })); +})); + +server.listen(0, common.mustCall(() => { + const port = server.address().port; + const client = http2.connect(`http://localhost:${port}`); + + const countdown = new Countdown(serverHttp2StreamCreationCount, () => { + client.close(); + server.close(); + + const timings = Object.values(map); + assert.strictEqual(timings.length, serverHttp2StreamCreationCount); + + for (const { createdTime, startTime } of timings) { + assert.ok(createdTime < startTime); + } + }); + + const stream = client.request({}); + stream.on('response', common.mustCall(() => { + countdown.dec(); + })); + + client.on('stream', common.mustCall((pushStream) => { + pushStream.on('push', common.mustCall(() => { + countdown.dec(); + })); + })); +})); diff --git a/test/parallel/test-diagnostics-channel-http2-server-stream-created.js b/test/parallel/test-diagnostics-channel-http2-server-stream-created.js new file mode 100644 index 00000000000000..b3b5fcd90aebe6 --- /dev/null +++ b/test/parallel/test-diagnostics-channel-http2-server-stream-created.js @@ -0,0 +1,60 @@ +'use strict'; + +const common = require('../common'); +if (!common.hasCrypto) + common.skip('missing crypto'); + +// This test ensures that the built-in HTTP/2 diagnostics channels are reporting +// the diagnostics messages for the 'http2.server.stream.created' channel when +// ServerHttp2Streams are created by both: +// - in response to an incoming 'stream' event from the client +// - the server calling ServerHttp2Stream#pushStream() + +const Countdown = require('../common/countdown'); +const assert = require('assert'); +const dc = require('diagnostics_channel'); +const http2 = require('http2'); +const { Duplex } = require('stream'); + +const serverHttp2StreamCreationCount = 2; + +dc.subscribe('http2.server.stream.created', common.mustCall(({ stream, headers }) => { + // Since ServerHttp2Stream is not exported from any module, this just checks + // if the stream is an instance of Duplex and the constructor name is + // 'ServerHttp2Stream'. + assert.ok(stream instanceof Duplex); + assert.strictEqual(stream.constructor.name, 'ServerHttp2Stream'); + assert.ok(headers && !Array.isArray(headers) && typeof headers === 'object'); +}, serverHttp2StreamCreationCount)); + +const server = http2.createServer(); +server.on('stream', common.mustCall((stream) => { + stream.respond(); + stream.end(); + + stream.pushStream({}, common.mustSucceed((pushStream) => { + pushStream.respond(); + pushStream.end(); + })); +})); + +server.listen(0, common.mustCall(() => { + const port = server.address().port; + const client = http2.connect(`http://localhost:${port}`); + + const countdown = new Countdown(serverHttp2StreamCreationCount, () => { + client.close(); + server.close(); + }); + + const stream = client.request({}); + stream.on('response', common.mustCall(() => { + countdown.dec(); + })); + + client.on('stream', common.mustCall((pushStream) => { + pushStream.on('push', common.mustCall(() => { + countdown.dec(); + })); + })); +})); diff --git a/test/parallel/test-diagnostics-channel-http2-server-stream-error.js b/test/parallel/test-diagnostics-channel-http2-server-stream-error.js new file mode 100644 index 00000000000000..ea4f49e200c88b --- /dev/null +++ b/test/parallel/test-diagnostics-channel-http2-server-stream-error.js @@ -0,0 +1,53 @@ +'use strict'; + +const common = require('../common'); +if (!common.hasCrypto) + common.skip('missing crypto'); + +// This test ensures that the built-in HTTP/2 diagnostics channels are reporting +// the diagnostics messages for the 'http2.server.stream.error' channel when +// an error occurs during the processing of a ServerHttp2Stream. + +const assert = require('assert'); +const dc = require('diagnostics_channel'); +const http2 = require('http2'); +const { Duplex } = require('stream'); + +let expectedError = null; + +dc.subscribe('http2.server.stream.error', common.mustCall(({ stream, error }) => { + // Since ServerHttp2Stream is not exported from any module, this just checks + // if the stream is an instance of Duplex and the constructor name is + // 'ServerHttp2Stream'. + assert.ok(stream instanceof Duplex); + assert.strictEqual(stream.constructor.name, 'ServerHttp2Stream'); + assert.strictEqual(stream.closed, true); + assert.strictEqual(stream.destroyed, true); + + assert.ok(error); + assert.strictEqual(error, expectedError); +})); + +const server = http2.createServer(); + +server.on('stream', common.mustCall((stream) => { + stream.on('error', common.mustCall((err) => { + assert.strictEqual(err, expectedError); + })); + + expectedError = new Error('HTTP/2 server stream error'); + stream.destroy(expectedError); +})); + +server.listen(0, common.mustCall(() => { + const port = server.address().port; + const client = http2.connect(`http://localhost:${port}`); + + const stream = client.request({}); + stream.on('error', common.mustCall((err) => { + assert.strictEqual(err.code, 'ERR_HTTP2_STREAM_ERROR'); + + client.close(); + server.close(); + })); +})); diff --git a/test/parallel/test-diagnostics-channel-http2-server-stream-finish.js b/test/parallel/test-diagnostics-channel-http2-server-stream-finish.js new file mode 100644 index 00000000000000..6a27cc1408ad77 --- /dev/null +++ b/test/parallel/test-diagnostics-channel-http2-server-stream-finish.js @@ -0,0 +1,61 @@ +'use strict'; + +const common = require('../common'); +if (!common.hasCrypto) + common.skip('missing crypto'); + +// This test ensures that the built-in HTTP/2 diagnostics channels are reporting +// the diagnostics messages for the 'http2.server.stream.finish' channel when +// ServerHttp2Streams#respond() sends a regular stream as well as a push stream. + +const Countdown = require('../common/countdown'); +const assert = require('assert'); +const dc = require('diagnostics_channel'); +const http2 = require('http2'); +const { Duplex } = require('stream'); + +const serverHttp2StreamFinishCount = 2; + +dc.subscribe('http2.server.stream.finish', common.mustCall(({ stream, headers, flags }) => { + // Since ServerHttp2Stream is not exported from any module, this just checks + // if the stream is an instance of Duplex and the constructor name is + // 'ServerHttp2Stream'. + assert.ok(stream instanceof Duplex); + assert.strictEqual(stream.constructor.name, 'ServerHttp2Stream'); + + assert.ok(headers && !Array.isArray(headers) && typeof headers === 'object'); + + assert.strictEqual(typeof flags, 'number'); +}, serverHttp2StreamFinishCount)); + +const server = http2.createServer(); +server.on('stream', common.mustCall((stream) => { + stream.respond(); + stream.end(); + + stream.pushStream({}, common.mustSucceed((pushStream) => { + pushStream.respond(); + pushStream.end(); + })); +})); + +server.listen(0, common.mustCall(() => { + const port = server.address().port; + const client = http2.connect(`http://localhost:${port}`); + + const countdown = new Countdown(serverHttp2StreamFinishCount, () => { + client.close(); + server.close(); + }); + + const stream = client.request({}); + stream.on('response', common.mustCall(() => { + countdown.dec(); + })); + + client.on('stream', common.mustCall((pushStream) => { + pushStream.on('push', common.mustCall(() => { + countdown.dec(); + })); + })); +})); diff --git a/test/parallel/test-diagnostics-channel-http2-server-stream-start.js b/test/parallel/test-diagnostics-channel-http2-server-stream-start.js new file mode 100644 index 00000000000000..b672037deb95a6 --- /dev/null +++ b/test/parallel/test-diagnostics-channel-http2-server-stream-start.js @@ -0,0 +1,60 @@ +'use strict'; + +const common = require('../common'); +if (!common.hasCrypto) + common.skip('missing crypto'); + +// This test ensures that the built-in HTTP/2 diagnostics channels are reporting +// the diagnostics messages for the 'http2.server.stream.start' channel when +// ServerHttp2Streams are started by both: +// - in response to an incoming 'stream' event from the client +// - the server calling ServerHttp2Stream#pushStream() + +const Countdown = require('../common/countdown'); +const assert = require('assert'); +const dc = require('diagnostics_channel'); +const http2 = require('http2'); +const { Duplex } = require('stream'); + +const serverHttp2StreamCreationCount = 2; + +dc.subscribe('http2.server.stream.start', common.mustCall(({ stream, headers }) => { + // Since ServerHttp2Stream is not exported from any module, this just checks + // if the stream is an instance of Duplex and the constructor name is + // 'ServerHttp2Stream'. + assert.ok(stream instanceof Duplex); + assert.strictEqual(stream.constructor.name, 'ServerHttp2Stream'); + assert.ok(headers && !Array.isArray(headers) && typeof headers === 'object'); +}, serverHttp2StreamCreationCount)); + +const server = http2.createServer(); +server.on('stream', common.mustCall((stream) => { + stream.respond(); + stream.end(); + + stream.pushStream({}, common.mustSucceed((pushStream) => { + pushStream.respond(); + pushStream.end(); + })); +})); + +server.listen(0, common.mustCall(() => { + const port = server.address().port; + const client = http2.connect(`http://localhost:${port}`); + + const countdown = new Countdown(serverHttp2StreamCreationCount, () => { + client.close(); + server.close(); + }); + + const stream = client.request({}); + stream.on('response', common.mustCall(() => { + countdown.dec(); + })); + + client.on('stream', common.mustCall((pushStream) => { + pushStream.on('push', common.mustCall(() => { + countdown.dec(); + })); + })); +})); diff --git a/test/parallel/test-diagnostics-channel-net-client-socket-tls.js b/test/parallel/test-diagnostics-channel-net-client-socket-tls.js new file mode 100644 index 00000000000000..c887376fd288c9 --- /dev/null +++ b/test/parallel/test-diagnostics-channel-net-client-socket-tls.js @@ -0,0 +1,32 @@ +'use strict'; +const common = require('../common'); +if (!common.hasCrypto) + common.skip('missing crypto'); + +// This test ensures that the 'net.client.socket' diagnostics channel publishes +// a message when tls.connect() is used to create a socket connection. + +const assert = require('assert'); +const dc = require('diagnostics_channel'); +const fixtures = require('../common/fixtures'); +const tls = require('tls'); + +const options = { + key: fixtures.readKey('agent1-key.pem'), + cert: fixtures.readKey('agent1-cert.pem'), + rejectUnauthorized: false, +}; + +dc.subscribe('net.client.socket', common.mustCall(({ socket }) => { + assert.strictEqual(socket instanceof tls.TLSSocket, true); +})); + +const server = tls.createServer(options, common.mustCall((socket) => { + socket.destroy(); + server.close(); +})); + +server.listen({ port: 0 }, common.mustCall(() => { + const { port } = server.address(); + tls.connect(port, options); +})); diff --git a/test/parallel/test-diagnostics-channel-net.js b/test/parallel/test-diagnostics-channel-net.js index dc84a5b4e1db60..4a959ece277e84 100644 --- a/test/parallel/test-diagnostics-channel-net.js +++ b/test/parallel/test-diagnostics-channel-net.js @@ -1,5 +1,6 @@ 'use strict'; const common = require('../common'); +const Countdown = require('../common/countdown'); const assert = require('assert'); const net = require('net'); const dc = require('diagnostics_channel'); @@ -18,19 +19,23 @@ function testDiagnosticChannel(subscribers, test, after) { const testSuccessfulListen = common.mustCall(() => { let cb; - const server = net.createServer(common.mustCall((socket) => { - socket.destroy(); + const netClientSocketCount = 3; + const countdown = new Countdown(netClientSocketCount, () => { server.close(); cb(); - })); + }); + const server = net.createServer(common.mustCall((socket) => { + socket.destroy(); + countdown.dec(); + }, netClientSocketCount)); dc.subscribe('net.client.socket', common.mustCall(({ socket }) => { assert.strictEqual(isNetSocket(socket), true); - })); + }, netClientSocketCount)); dc.subscribe('net.server.socket', common.mustCall(({ socket }) => { assert.strictEqual(isNetSocket(socket), true); - })); + }, netClientSocketCount)); testDiagnosticChannel( { @@ -48,8 +53,13 @@ const testSuccessfulListen = common.mustCall(() => { common.mustCall((callback) => { cb = callback; server.listen({ port: 0, customOption: true }, () => { + // All supported ways of creating a net client socket connection. const { port } = server.address(); net.connect(port); + + net.createConnection(port); + + new net.Socket().connect(port); }); }), testFailingListen diff --git a/test/parallel/test-dns.js b/test/parallel/test-dns.js index a6b3e459aa00a5..7d67b09d58fc5d 100644 --- a/test/parallel/test-dns.js +++ b/test/parallel/test-dns.js @@ -415,7 +415,7 @@ assert.throws(() => { (answer) => Object.assign({ domain }, answer) ), }), port, address); - }, cases.length * 2 - 1)); + }, cases.length * 2)); server.bind(0, common.mustCall(() => { const address = server.address(); diff --git a/test/parallel/test-filehandle-autoclose.mjs b/test/parallel/test-filehandle-autoclose.mjs new file mode 100644 index 00000000000000..cc8733f3ef47e2 --- /dev/null +++ b/test/parallel/test-filehandle-autoclose.mjs @@ -0,0 +1,17 @@ +import '../common/index.mjs'; +import { open } from 'node:fs/promises'; +import { rejects } from 'node:assert'; + +{ + const fh = await open(new URL(import.meta.url)); + + // TODO: remove autoClose option when it becomes default + const readableStream = fh.readableWebStream({ autoClose: true }); + + // Consume the stream + await new Response(readableStream).text(); + + // If reading the FileHandle after the stream is consumed fails, + // then we assume the autoClose option worked as expected. + await rejects(fh.read(), { code: 'EBADF' }); +} diff --git a/test/parallel/test-fs-constants.js b/test/parallel/test-fs-constants.js index 49bcabd80873b4..cdecfe5591631a 100644 --- a/test/parallel/test-fs-constants.js +++ b/test/parallel/test-fs-constants.js @@ -6,3 +6,72 @@ const assert = require('assert'); // Check if the two constants accepted by chmod() on Windows are defined. assert.notStrictEqual(fs.constants.S_IRUSR, undefined); assert.notStrictEqual(fs.constants.S_IWUSR, undefined); + +// Check null prototype. +assert.strictEqual(Object.getPrototypeOf(fs.constants), null); + +const knownFsConstantNames = [ + 'UV_FS_SYMLINK_DIR', + 'UV_FS_SYMLINK_JUNCTION', + 'O_RDONLY', + 'O_WRONLY', + 'O_RDWR', + 'UV_DIRENT_UNKNOWN', + 'UV_DIRENT_FILE', + 'UV_DIRENT_DIR', + 'UV_DIRENT_LINK', + 'UV_DIRENT_FIFO', + 'UV_DIRENT_SOCKET', + 'UV_DIRENT_CHAR', + 'UV_DIRENT_BLOCK', + 'S_IFMT', + 'S_IFREG', + 'S_IFDIR', + 'S_IFCHR', + 'S_IFBLK', + 'S_IFIFO', + 'S_IFLNK', + 'S_IFSOCK', + 'O_CREAT', + 'O_EXCL', + 'UV_FS_O_FILEMAP', + 'O_NOCTTY', + 'O_TRUNC', + 'O_APPEND', + 'O_DIRECTORY', + 'O_EXCL', + 'O_NOATIME', + 'O_NOFOLLOW', + 'O_SYNC', + 'O_DSYNC', + 'O_SYMLINK', + 'O_DIRECT', + 'O_NONBLOCK', + 'S_IRWXU', + 'S_IRUSR', + 'S_IWUSR', + 'S_IXUSR', + 'S_IRWXG', + 'S_IRGRP', + 'S_IWGRP', + 'S_IXGRP', + 'S_IRWXO', + 'S_IROTH', + 'S_IWOTH', + 'S_IXOTH', + 'F_OK', + 'R_OK', + 'W_OK', + 'X_OK', + 'UV_FS_COPYFILE_EXCL', + 'COPYFILE_EXCL', + 'UV_FS_COPYFILE_FICLONE', + 'COPYFILE_FICLONE', + 'UV_FS_COPYFILE_FICLONE_FORCE', + 'COPYFILE_FICLONE_FORCE', +]; +const fsConstantNames = Object.keys(fs.constants); +const unknownFsConstantNames = fsConstantNames.filter((constant) => { + return !knownFsConstantNames.includes(constant); +}); +assert.deepStrictEqual(unknownFsConstantNames, [], `Unknown fs.constants: ${unknownFsConstantNames.join(', ')}`); diff --git a/test/parallel/test-fs-cp.mjs b/test/parallel/test-fs-cp.mjs index 260a1449d1a953..c66e6330eb4707 100644 --- a/test/parallel/test-fs-cp.mjs +++ b/test/parallel/test-fs-cp.mjs @@ -493,6 +493,9 @@ if (!isWindows && !isInsideDirWithUnusualChars) { const dest = nextdir(); mkdirSync(dest, mustNotMutateObjectDeep({ recursive: true })); writeFileSync(join(src, 'foo.txt'), 'foo', mustNotMutateObjectDeep({ mode: 0o444 })); + // Small wait to make sure that destStat.mtime.getTime() would produce a time + // different from srcStat.mtime.getTime() if preserveTimestamps wasn't set to true + await setTimeout(5); cpSync(src, dest, mustNotMutateObjectDeep({ preserveTimestamps: true, recursive: true })); assertDirEquivalent(src, dest); const srcStat = lstatSync(join(src, 'foo.txt')); diff --git a/test/parallel/test-fs-glob.mjs b/test/parallel/test-fs-glob.mjs index 077c05279915b5..b3708f466379fa 100644 --- a/test/parallel/test-fs-glob.mjs +++ b/test/parallel/test-fs-glob.mjs @@ -4,6 +4,7 @@ import { resolve, dirname, sep, relative, join, isAbsolute } from 'node:path'; import { mkdir, writeFile, symlink, glob as asyncGlob } from 'node:fs/promises'; import { glob, globSync, Dirent } from 'node:fs'; import { test, describe } from 'node:test'; +import { pathToFileURL } from 'node:url'; import { promisify } from 'node:util'; import assert from 'node:assert'; @@ -338,6 +339,39 @@ describe('fsPromises glob', function() { } }); +describe('glob - with file: URL as cwd', function() { + const promisified = promisify(glob); + for (const [pattern, expected] of Object.entries(patterns)) { + test(pattern, async () => { + const actual = (await promisified(pattern, { cwd: pathToFileURL(fixtureDir) })).sort(); + const normalized = expected.filter(Boolean).map((item) => item.replaceAll('/', sep)).sort(); + assert.deepStrictEqual(actual, normalized); + }); + } +}); + +describe('globSync - with file: URL as cwd', function() { + for (const [pattern, expected] of Object.entries(patterns)) { + test(pattern, () => { + const actual = globSync(pattern, { cwd: pathToFileURL(fixtureDir) }).sort(); + const normalized = expected.filter(Boolean).map((item) => item.replaceAll('/', sep)).sort(); + assert.deepStrictEqual(actual, normalized); + }); + } +}); + +describe('fsPromises.glob - with file: URL as cwd', function() { + for (const [pattern, expected] of Object.entries(patterns)) { + test(pattern, async () => { + const actual = []; + for await (const item of asyncGlob(pattern, { cwd: pathToFileURL(fixtureDir) })) actual.push(item); + actual.sort(); + const normalized = expected.filter(Boolean).map((item) => item.replaceAll('/', sep)).sort(); + assert.deepStrictEqual(actual, normalized); + }); + } +}); + const normalizeDirent = (dirent) => relative(fixtureDir, join(dirent.parentPath, dirent.name)); // The call to `join()` with only one argument is important, as // it ensures that the proper path seperators are applied. diff --git a/test/parallel/test-fs-opendir.js b/test/parallel/test-fs-opendir.js index 8b8fc161eee661..8e5fb27eb9fa3a 100644 --- a/test/parallel/test-fs-opendir.js +++ b/test/parallel/test-fs-opendir.js @@ -161,7 +161,7 @@ async function doAsyncIterBreakTest() { break; } - await assert.rejects(async () => dir.read(), dirclosedError); + await assert.rejects(dir.read(), dirclosedError); } doAsyncIterBreakTest().then(common.mustCall()); @@ -173,7 +173,7 @@ async function doAsyncIterReturnTest() { } })(); - await assert.rejects(async () => dir.read(), dirclosedError); + await assert.rejects(dir.read(), dirclosedError); } doAsyncIterReturnTest().then(common.mustCall()); @@ -189,7 +189,7 @@ async function doAsyncIterThrowTest() { } } - await assert.rejects(async () => dir.read(), dirclosedError); + await assert.rejects(dir.read(), dirclosedError); } doAsyncIterThrowTest().then(common.mustCall()); diff --git a/test/parallel/test-fs-promises-file-handle-dispose.js b/test/parallel/test-fs-promises-file-handle-dispose.js index 406430eef4a204..2d58d1ed37e4d7 100644 --- a/test/parallel/test-fs-promises-file-handle-dispose.js +++ b/test/parallel/test-fs-promises-file-handle-dispose.js @@ -1,12 +1,22 @@ 'use strict'; const common = require('../common'); -const { promises: fs } = require('fs'); +const assert = require('assert'); +const { opendirSync, promises: fs } = require('fs'); -async function doOpen() { +async function explicitCall() { const fh = await fs.open(__filename); fh.on('close', common.mustCall()); await fh[Symbol.asyncDispose](); + + const dh = await fs.opendir(__dirname); + await dh[Symbol.asyncDispose](); + await assert.rejects(dh.read(), { code: 'ERR_DIR_CLOSED' }); + + const dhSync = opendirSync(__dirname); + dhSync[Symbol.dispose](); + assert.throws(() => dhSync.readSync(), { code: 'ERR_DIR_CLOSED' }); } -doOpen().then(common.mustCall()); +explicitCall().then(common.mustCall()); +// TODO(aduh95): add test for implicit calls, with `await using` syntax. diff --git a/test/parallel/test-http-client-parse-error.js b/test/parallel/test-http-client-parse-error.js index 5d0ad4b1463ed5..c2167aaabcf8fd 100644 --- a/test/parallel/test-http-client-parse-error.js +++ b/test/parallel/test-http-client-parse-error.js @@ -47,7 +47,7 @@ server.listen(0, common.mustCall(() => { assert.strictEqual(req.socket.listenerCount('end'), 1); common.expectsError({ code: 'HPE_INVALID_CONSTANT', - message: 'Parse Error: Expected HTTP/' + message: 'Parse Error: Expected HTTP/, RTSP/ or ICE/' })(e); countdown.dec(); })); diff --git a/test/parallel/test-http2-client-socket-destroy.js b/test/parallel/test-http2-client-socket-destroy.js index 2cc6ef1e4ea4a8..1c0fa54f11c326 100644 --- a/test/parallel/test-http2-client-socket-destroy.js +++ b/test/parallel/test-http2-client-socket-destroy.js @@ -15,6 +15,7 @@ const server = h2.createServer(); // We use the lower-level API here server.on('stream', common.mustCall((stream) => { + stream.on('error', () => {}); stream.on('aborted', common.mustCall()); stream.on('close', common.mustCall()); stream.respond(); diff --git a/test/parallel/test-http2-debug.js b/test/parallel/test-http2-debug.js index a465f74af24698..5f2f6c54da7cab 100644 --- a/test/parallel/test-http2-debug.js +++ b/test/parallel/test-http2-debug.js @@ -1,27 +1,31 @@ 'use strict'; + const common = require('../common'); if (!common.hasCrypto) common.skip('missing crypto'); const assert = require('assert'); -const child_process = require('child_process'); +const { spawnSyncAndAssert } = require('../common/child_process'); const path = require('path'); -process.env.NODE_DEBUG_NATIVE = 'http2'; -process.env.NODE_DEBUG = 'http2'; -const { stdout, stderr } = child_process.spawnSync(process.execPath, [ +spawnSyncAndAssert(process.execPath, [ path.resolve(__dirname, 'test-http2-ping.js'), -], { encoding: 'utf8' }); - -assert(stderr.match(/Setting the NODE_DEBUG environment variable to 'http2' can expose sensitive data \(such as passwords, tokens and authentication headers\) in the resulting log\.\r?\n/), - stderr); -assert(stderr.match(/Http2Session client \(\d+\) handling data frame for stream \d+\r?\n/), - stderr); -assert(stderr.match(/HttpStream \d+ \(\d+\) \[Http2Session client \(\d+\)\] reading starting\r?\n/), - stderr); -assert(stderr.match(/HttpStream \d+ \(\d+\) \[Http2Session client \(\d+\)\] closed with code 0\r?\n/), - stderr); -assert(stderr.match(/HttpStream \d+ \(\d+\) \[Http2Session server \(\d+\)\] closed with code 0\r?\n/), - stderr); -assert(stderr.match(/HttpStream \d+ \(\d+\) \[Http2Session server \(\d+\)\] tearing down stream\r?\n/), - stderr); -assert.strictEqual(stdout.trim(), ''); +], { + env: { + ...process.env, + NODE_DEBUG: 'http2', + NODE_DEBUG_NATIVE: 'http2', + }, +}, { + trim: true, + stderr(output) { + assert.match(output, + /Setting the NODE_DEBUG environment variable to 'http2' can expose sensitive data/); + assert.match(output, /\(such as passwords, tokens and authentication headers\) in the resulting log\.\r?\n/); + assert.match(output, /Http2Session client \(\d+\) handling data frame for stream \d+\r?\n/); + assert.match(output, /HttpStream \d+ \(\d+\) \[Http2Session client \(\d+\)\] reading starting\r?\n/); + assert.match(output, /HttpStream \d+ \(\d+\) \[Http2Session client \(\d+\)\] closed with code 0\r?\n/); + assert.match(output, /HttpStream \d+ \(\d+\) \[Http2Session server \(\d+\)\] closed with code 0\r?\n/); + assert.match(output, /HttpStream \d+ \(\d+\) \[Http2Session server \(\d+\)\] tearing down stream\r?\n/); + }, + stdout: '' +}); diff --git a/test/parallel/test-http2-invalidheaderfield.js b/test/parallel/test-http2-invalidheaderfield.js index bc18f2ba42634a..d6799160f3f020 100644 --- a/test/parallel/test-http2-invalidheaderfield.js +++ b/test/parallel/test-http2-invalidheaderfield.js @@ -8,7 +8,7 @@ if (!common.hasCrypto) { common.skip('missing crypto'); } // Capitalized headers const http2 = require('http2'); -const { throws, strictEqual } = require('assert'); +const { throws } = require('assert'); { const server = http2.createServer(common.mustCall((req, res) => { @@ -42,45 +42,40 @@ const { throws, strictEqual } = require('assert'); const server = http2.createServer(); server.listen(0, common.mustCall(() => { const session = http2.connect(`http://localhost:${server.address().port}`); - session.on('error', common.mustCall((e) => { - strictEqual(e.code, 'ERR_INVALID_HTTP_TOKEN'); - server.close(); - })); throws(() => { session.request({ 't est': 123 }); }, { code: 'ERR_INVALID_HTTP_TOKEN' }); + session.close(); + server.close(); })); } - { const server = http2.createServer(); server.listen(0, common.mustCall(() => { const session = http2.connect(`http://localhost:${server.address().port}`); - session.on('error', common.mustCall((e) => { - strictEqual(e.code, 'ERR_INVALID_HTTP_TOKEN'); - server.close(); - })); throws(() => { session.request({ ' test': 123 }); }, { code: 'ERR_INVALID_HTTP_TOKEN' }); + session.close(); + server.close(); })); } { const server = http2.createServer(); server.listen(0, common.mustCall(() => { - const session4 = http2.connect(`http://localhost:${server.address().port}`); + const session = http2.connect(`http://localhost:${server.address().port}`); throws(() => { - session4.request({ ':test': 123 }); + session.request({ ':test': 123 }); }, { code: 'ERR_HTTP2_INVALID_PSEUDOHEADER' }); - session4.close(); + session.close(); server.close(); })); } diff --git a/test/parallel/test-http2-invalidheaderfields-client.js b/test/parallel/test-http2-invalidheaderfields-client.js index a5681970faab27..cfca6c30b28db3 100644 --- a/test/parallel/test-http2-invalidheaderfields-client.js +++ b/test/parallel/test-http2-invalidheaderfields-client.js @@ -14,10 +14,8 @@ server1.listen(0, common.mustCall(() => { }, { code: 'ERR_INVALID_HTTP_TOKEN' }); - session.on('error', common.mustCall((e) => { - assert.strictEqual(e.code, 'ERR_INVALID_HTTP_TOKEN'); - server1.close(); - })); + session.close(); + server1.close(); })); const server2 = http2.createServer(common.mustCall((req, res) => { diff --git a/test/parallel/test-http2-raw-headers.js b/test/parallel/test-http2-raw-headers.js new file mode 100644 index 00000000000000..cbcc73692b0a3d --- /dev/null +++ b/test/parallel/test-http2-raw-headers.js @@ -0,0 +1,48 @@ +'use strict'; + +const common = require('../common'); +if (!common.hasCrypto) + common.skip('missing crypto'); +const assert = require('assert'); +const http2 = require('http2'); + +{ + const server = http2.createServer(); + server.on('stream', common.mustCall((stream, headers, flags, rawHeaders) => { + assert.deepStrictEqual(rawHeaders, [ + ':path', '/foobar', + ':scheme', 'http', + ':authority', `localhost:${server.address().port}`, + ':method', 'GET', + 'a', 'b', + 'x-foo', 'bar', + 'a', 'c', + ]); + stream.respond({ + ':status': 200 + }); + stream.end(); + })); + + + server.listen(0, common.mustCall(() => { + const port = server.address().port; + const client = http2.connect(`http://localhost:${port}`); + + const req = client.request([ + ':path', '/foobar', + ':scheme', 'http', + ':authority', `localhost:${server.address().port}`, + ':method', 'GET', + 'a', 'b', + 'x-FOO', 'bar', + 'a', 'c', + ]).end(); + + req.on('response', common.mustCall((headers) => { + assert.strictEqual(headers[':status'], 200); + client.close(); + server.close(); + })); + })); +} diff --git a/test/parallel/test-http2-sensitive-headers.js b/test/parallel/test-http2-sensitive-headers.js index aadedc1ba831b5..bbd00ae0cdd117 100644 --- a/test/parallel/test-http2-sensitive-headers.js +++ b/test/parallel/test-http2-sensitive-headers.js @@ -45,3 +45,41 @@ const { duplexPair } = require('stream'); req.resume(); req.end(); } + +{ + const server = http2.createServer(); + server.on('stream', common.mustCall((stream, headers) => { + assert.deepStrictEqual( + headers[http2.sensitiveHeaders], + ['secret'] + ); + stream.respond({ ':status': 200 }); + stream.end(); + })); + + const [ clientSide, serverSide ] = duplexPair(); + server.emit('connection', serverSide); + + const client = http2.connect('http://localhost:80', { + createConnection: common.mustCall(() => clientSide) + }); + + const rawHeaders = [ + ':path', '/', + 'secret', 'secret-value', + ]; + rawHeaders[http2.sensitiveHeaders] = ['secret']; + + const req = client.request(rawHeaders); + + req.on('response', common.mustCall((headers) => { + assert.strictEqual(headers[':status'], 200); + })); + + req.on('end', common.mustCall(() => { + clientSide.destroy(); + clientSide.end(); + })); + req.resume(); + req.end(); +} diff --git a/test/parallel/test-http2-server-rfc-9113-client.js b/test/parallel/test-http2-server-rfc-9113-client.js new file mode 100644 index 00000000000000..caeb7e1fd74361 --- /dev/null +++ b/test/parallel/test-http2-server-rfc-9113-client.js @@ -0,0 +1,80 @@ +'use strict'; + +const common = require('../common'); +if (!common.hasCrypto) + common.skip('missing crypto'); +const assert = require('assert'); +const http2 = require('http2'); +const body = + '

    this is some data

    '; + +const server = http2.createServer((req, res) => { + res.setHeader('foobar', 'baz '); + res.setHeader('X-POWERED-BY', 'node-test\t'); + res.setHeader('x-h2-header', '\tconnection-test'); + res.setHeader('x-h2-header-2', ' connection-test'); + res.setHeader('x-h2-header-3', 'connection-test '); + res.end(body); +}); + +const server2 = http2.createServer((req, res) => { + res.setHeader('foobar', 'baz '); + res.setHeader('X-POWERED-BY', 'node-test\t'); + res.setHeader('x-h2-header', '\tconnection-test'); + res.setHeader('x-h2-header-2', ' connection-test'); + res.setHeader('x-h2-header-3', 'connection-test '); + res.end(body); +}); + +server.listen(0, common.mustCall(() => { + server2.listen(0, common.mustCall(() => { + const client = http2.connect(`http://localhost:${server.address().port}`); + const client2 = http2.connect(`http://localhost:${server2.address().port}`, { strictFieldWhitespaceValidation: false }); + const headers = { ':path': '/' }; + const req = client.request(headers); + + req.setEncoding('utf8'); + req.on('response', common.mustCall(function(headers) { + assert.strictEqual(headers.foobar, undefined); + assert.strictEqual(headers['x-powered-by'], undefined); + assert.strictEqual(headers['x-powered-by'], undefined); + assert.strictEqual(headers['x-h2-header'], undefined); + assert.strictEqual(headers['x-h2-header-2'], undefined); + assert.strictEqual(headers['x-h2-header-3'], undefined); + })); + + let data = ''; + req.on('data', (d) => data += d); + req.on('end', () => { + assert.strictEqual(body, data); + client.close(); + client.on('close', common.mustCall(() => { + server.close(); + })); + + const req2 = client2.request(headers); + let data2 = ''; + req2.setEncoding('utf8'); + req2.on('response', common.mustCall(function(headers) { + assert.strictEqual(headers.foobar, 'baz '); + assert.strictEqual(headers['x-powered-by'], 'node-test\t'); + assert.strictEqual(headers['x-h2-header'], '\tconnection-test'); + assert.strictEqual(headers['x-h2-header-2'], ' connection-test'); + assert.strictEqual(headers['x-h2-header-3'], 'connection-test '); + })); + req2.on('data', (d) => data2 += d); + req2.on('end', () => { + assert.strictEqual(body, data2); + client2.close(); + client2.on('close', common.mustCall(() => { + server2.close(); + })); + }); + req2.end(); + }); + + req.end(); + })); +})); + +server.on('error', common.mustNotCall()); diff --git a/test/parallel/test-http2-server-rfc-9113-server.js b/test/parallel/test-http2-server-rfc-9113-server.js new file mode 100644 index 00000000000000..b05bdb2f8cbc37 --- /dev/null +++ b/test/parallel/test-http2-server-rfc-9113-server.js @@ -0,0 +1,83 @@ +'use strict'; + +const common = require('../common'); +if (!common.hasCrypto) + common.skip('missing crypto'); +const assert = require('assert'); +const http2 = require('http2'); +const body = + '

    this is some data

    '; + +const server = http2.createServer((req, res) => { + assert.strictEqual(req.headers['x-powered-by'], undefined); + assert.strictEqual(req.headers.foobar, undefined); + assert.strictEqual(req.headers['x-h2-header'], undefined); + assert.strictEqual(req.headers['x-h2-header-2'], undefined); + assert.strictEqual(req.headers['x-h2-header-3'], undefined); + assert.strictEqual(req.headers['x-h2-header-4'], undefined); + res.writeHead(200); + res.end(body); +}); + +const server2 = http2.createServer({ strictFieldWhitespaceValidation: false }, (req, res) => { + assert.strictEqual(req.headers.foobar, 'baz '); + assert.strictEqual(req.headers['x-powered-by'], 'node-test\t'); + assert.strictEqual(req.headers['x-h2-header'], '\tconnection-test'); + assert.strictEqual(req.headers['x-h2-header-2'], ' connection-test'); + assert.strictEqual(req.headers['x-h2-header-3'], 'connection-test '); + assert.strictEqual(req.headers['x-h2-header-4'], 'connection-test\t'); + res.writeHead(200); + res.end(body); +}); + +server.listen(0, common.mustCall(() => { + server2.listen(0, common.mustCall(() => { + const client = http2.connect(`http://localhost:${server.address().port}`); + const client2 = http2.connect(`http://localhost:${server2.address().port}`); + const headers = { + 'foobar': 'baz ', + ':path': '/', + 'x-powered-by': 'node-test\t', + 'x-h2-header': '\tconnection-test', + 'x-h2-header-2': ' connection-test', + 'x-h2-header-3': 'connection-test ', + 'x-h2-header-4': 'connection-test\t' + }; + const req = client.request(headers); + + req.setEncoding('utf8'); + req.on('response', common.mustCall(function(headers) { + assert.strictEqual(headers[':status'], 200); + })); + + let data = ''; + req.on('data', (d) => data += d); + req.on('end', () => { + assert.strictEqual(body, data); + client.close(); + client.on('close', common.mustCall(() => { + server.close(); + })); + + const req2 = client2.request(headers); + let data2 = ''; + req2.setEncoding('utf8'); + req2.on('response', common.mustCall(function(headers) { + assert.strictEqual(headers[':status'], 200); + })); + req2.on('data', (d) => data2 += d); + req2.on('end', () => { + assert.strictEqual(body, data2); + client2.close(); + client2.on('close', common.mustCall(() => { + server2.close(); + })); + }); + req2.end(); + }); + + req.end(); + })); +})); + +server.on('error', common.mustNotCall()); diff --git a/test/parallel/test-http2-server-timeout.js b/test/parallel/test-http2-server-timeout.js old mode 100755 new mode 100644 diff --git a/test/parallel/test-http2-util-assert-valid-pseudoheader.js b/test/parallel/test-http2-util-assert-valid-pseudoheader.js index f86793c69efdf3..bd995f0338f106 100644 --- a/test/parallel/test-http2-util-assert-valid-pseudoheader.js +++ b/test/parallel/test-http2-util-assert-valid-pseudoheader.js @@ -5,19 +5,19 @@ require('../common'); const assert = require('assert'); // Tests the assertValidPseudoHeader function that is used within the -// mapToHeaders function. The assert function is not exported so we -// have to test it through mapToHeaders +// buildNgHeaderString function. The assert function is not exported so we +// have to test it through buildNgHeaderString -const { mapToHeaders } = require('internal/http2/util'); +const { buildNgHeaderString } = require('internal/http2/util'); // These should not throw -mapToHeaders({ ':status': 'a' }); -mapToHeaders({ ':path': 'a' }); -mapToHeaders({ ':authority': 'a' }); -mapToHeaders({ ':scheme': 'a' }); -mapToHeaders({ ':method': 'a' }); +buildNgHeaderString({ ':status': 'a' }); +buildNgHeaderString({ ':path': 'a' }); +buildNgHeaderString({ ':authority': 'a' }); +buildNgHeaderString({ ':scheme': 'a' }); +buildNgHeaderString({ ':method': 'a' }); -assert.throws(() => mapToHeaders({ ':foo': 'a' }), { +assert.throws(() => buildNgHeaderString({ ':foo': 'a' }), { code: 'ERR_HTTP2_INVALID_PSEUDOHEADER', name: 'TypeError', message: '":foo" is an invalid pseudoheader or is used incorrectly' diff --git a/test/parallel/test-http2-util-headers-list.js b/test/parallel/test-http2-util-headers-list.js index f4221f5c17e589..0d1ac1d1b8c694 100644 --- a/test/parallel/test-http2-util-headers-list.js +++ b/test/parallel/test-http2-util-headers-list.js @@ -10,7 +10,7 @@ if (!common.hasCrypto) const assert = require('assert'); const { getAuthority, - mapToHeaders, + buildNgHeaderString, toHeaderObject } = require('internal/http2/util'); const { sensitiveHeaders } = require('http2'); @@ -106,7 +106,7 @@ const { }; assert.deepStrictEqual( - mapToHeaders(headers), + buildNgHeaderString(headers), [ [ ':path', 'abc\0', ':status', '200\0', 'abc', '1\0', 'xyz', '1\0', 'xyz', '2\0', 'xyz', '3\0', 'xyz', '4\0', 'bar', '1\0', '' ].join('\0'), 8 ] @@ -123,7 +123,7 @@ const { }; assert.deepStrictEqual( - mapToHeaders(headers), + buildNgHeaderString(headers), [ [ ':status', '200\0', ':path', 'abc\0', 'abc', '1\0', 'xyz', '1\0', 'xyz', '2\0', 'xyz', '3\0', 'xyz', '4\0', '' ].join('\0'), 7 ] ); @@ -140,7 +140,7 @@ const { }; assert.deepStrictEqual( - mapToHeaders(headers), + buildNgHeaderString(headers), [ [ ':status', '200\0', ':path', 'abc\0', 'abc', '1\0', 'xyz', '1\0', 'xyz', '2\0', 'xyz', '3\0', 'xyz', '4\0', '' ].join('\0'), 7 ] ); @@ -156,7 +156,7 @@ const { headers[':path'] = 'abc'; assert.deepStrictEqual( - mapToHeaders(headers), + buildNgHeaderString(headers), [ [ ':status', '200\0', ':path', 'abc\0', 'xyz', '1\0', 'xyz', '2\0', 'xyz', '3\0', 'xyz', '4\0', '' ].join('\0'), 6 ] ); @@ -169,7 +169,7 @@ const { 'set-cookie': ['foo=bar'] }; assert.deepStrictEqual( - mapToHeaders(headers), + buildNgHeaderString(headers), [ [ 'set-cookie', 'foo=bar\0', '' ].join('\0'), 1 ] ); } @@ -181,7 +181,7 @@ const { ':statuS': 204, }; - assert.throws(() => mapToHeaders(headers), { + assert.throws(() => buildNgHeaderString(headers), { code: 'ERR_HTTP2_HEADER_SINGLE_VALUE', name: 'TypeError', message: 'Header field ":status" must only have a single value' @@ -199,7 +199,7 @@ const { }; assert.deepStrictEqual( - mapToHeaders(headers), + buildNgHeaderString(headers), [ ':status\x00200\x00\x00:path\x00abc\x00\x00abc\x001\x00\x00' + 'xyz\x001\x00\x01xyz\x002\x00\x01xyz\x003\x00\x01xyz\x004\x00\x01', 7 ] ); @@ -248,7 +248,7 @@ const { HTTP2_HEADER_X_CONTENT_TYPE_OPTIONS, ].forEach((name) => { const msg = `Header field "${name}" must only have a single value`; - assert.throws(() => mapToHeaders({ [name]: [1, 2, 3] }), { + assert.throws(() => buildNgHeaderString({ [name]: [1, 2, 3] }), { code: 'ERR_HTTP2_HEADER_SINGLE_VALUE', message: msg }); @@ -285,7 +285,7 @@ const { HTTP2_HEADER_WWW_AUTHENTICATE, HTTP2_HEADER_X_FRAME_OPTIONS, ].forEach((name) => { - assert(!(mapToHeaders({ [name]: [1, 2, 3] }) instanceof Error), name); + assert(!(buildNgHeaderString({ [name]: [1, 2, 3] }) instanceof Error), name); }); [ @@ -304,7 +304,7 @@ const { 'Proxy-Connection', 'Keep-Alive', ].forEach((name) => { - assert.throws(() => mapToHeaders({ [name]: 'abc' }), { + assert.throws(() => buildNgHeaderString({ [name]: 'abc' }), { code: 'ERR_HTTP2_INVALID_CONNECTION_HEADERS', name: 'TypeError', message: 'HTTP/1 Connection specific headers are forbidden: ' + @@ -312,7 +312,7 @@ const { }); }); -assert.throws(() => mapToHeaders({ [HTTP2_HEADER_TE]: ['abc'] }), { +assert.throws(() => buildNgHeaderString({ [HTTP2_HEADER_TE]: ['abc'] }), { code: 'ERR_HTTP2_INVALID_CONNECTION_HEADERS', name: 'TypeError', message: 'HTTP/1 Connection specific headers are forbidden: ' + @@ -320,7 +320,7 @@ assert.throws(() => mapToHeaders({ [HTTP2_HEADER_TE]: ['abc'] }), { }); assert.throws( - () => mapToHeaders({ [HTTP2_HEADER_TE]: ['abc', 'trailers'] }), { + () => buildNgHeaderString({ [HTTP2_HEADER_TE]: ['abc', 'trailers'] }), { code: 'ERR_HTTP2_INVALID_CONNECTION_HEADERS', name: 'TypeError', message: 'HTTP/1 Connection specific headers are forbidden: ' + @@ -328,13 +328,13 @@ assert.throws( }); // These should not throw -mapToHeaders({ te: 'trailers' }); -mapToHeaders({ te: ['trailers'] }); +buildNgHeaderString({ te: 'trailers' }); +buildNgHeaderString({ te: ['trailers'] }); // HTTP/2 encourages use of Host instead of :authority when converting // from HTTP/1 to HTTP/2, so we no longer disallow it. // Refs: https://github.com/nodejs/node/issues/29858 -mapToHeaders({ [HTTP2_HEADER_HOST]: 'abc' }); +buildNgHeaderString({ [HTTP2_HEADER_HOST]: 'abc' }); // If both are present, the latter has priority assert.strictEqual(getAuthority({ diff --git a/test/parallel/test-http2-util-update-options-buffer.js b/test/parallel/test-http2-util-update-options-buffer.js index c370fe50c07439..26e220e6b7b507 100644 --- a/test/parallel/test-http2-util-update-options-buffer.js +++ b/test/parallel/test-http2-util-update-options-buffer.js @@ -25,7 +25,8 @@ const IDX_OPTIONS_MAX_SESSION_MEMORY = 8; const IDX_OPTIONS_MAX_SETTINGS = 9; const IDX_OPTIONS_STREAM_RESET_RATE = 10; const IDX_OPTIONS_STREAM_RESET_BURST = 11; -const IDX_OPTIONS_FLAGS = 12; +const IDX_OPTIONS_STRICT_HTTP_FIELD_WHITESPACE_VALIDATION = 12; +const IDX_OPTIONS_FLAGS = 13; { updateOptionsBuffer({ @@ -41,6 +42,7 @@ const IDX_OPTIONS_FLAGS = 12; maxSettings: 10, streamResetRate: 11, streamResetBurst: 12, + strictFieldWhitespaceValidation: false }); strictEqual(optionsBuffer[IDX_OPTIONS_MAX_DEFLATE_DYNAMIC_TABLE_SIZE], 1); @@ -55,6 +57,7 @@ const IDX_OPTIONS_FLAGS = 12; strictEqual(optionsBuffer[IDX_OPTIONS_MAX_SETTINGS], 10); strictEqual(optionsBuffer[IDX_OPTIONS_STREAM_RESET_RATE], 11); strictEqual(optionsBuffer[IDX_OPTIONS_STREAM_RESET_BURST], 12); + strictEqual(optionsBuffer[IDX_OPTIONS_STRICT_HTTP_FIELD_WHITESPACE_VALIDATION], 1); const flags = optionsBuffer[IDX_OPTIONS_FLAGS]; @@ -69,6 +72,7 @@ const IDX_OPTIONS_FLAGS = 12; ok(flags & (1 << IDX_OPTIONS_MAX_SETTINGS)); ok(flags & (1 << IDX_OPTIONS_STREAM_RESET_RATE)); ok(flags & (1 << IDX_OPTIONS_STREAM_RESET_BURST)); + ok(flags & (1 << IDX_OPTIONS_STRICT_HTTP_FIELD_WHITESPACE_VALIDATION)); } { diff --git a/test/parallel/test-https-agent-additional-options.js b/test/parallel/test-https-agent-additional-options.js index 543ee176fb6af3..000cb9d3d0c284 100644 --- a/test/parallel/test-https-agent-additional-options.js +++ b/test/parallel/test-https-agent-additional-options.js @@ -13,23 +13,31 @@ const options = { cert: fixtures.readKey('agent1-cert.pem'), ca: fixtures.readKey('ca1-cert.pem'), minVersion: 'TLSv1.1', - ciphers: 'ALL@SECLEVEL=0' }; +if (!process.features.openssl_is_boringssl) { + options.ciphers = 'ALL@SECLEVEL=0'; +} + const server = https.Server(options, (req, res) => { res.writeHead(200); res.end('hello world\n'); }); function getBaseOptions(port) { - return { + const baseOptions = { path: '/', port: port, ca: options.ca, rejectUnauthorized: true, servername: 'agent1', - ciphers: 'ALL@SECLEVEL=0' }; + + if (!process.features.openssl_is_boringssl) { + baseOptions.ciphers = 'ALL@SECLEVEL=0'; + } + + return baseOptions; } const updatedValues = new Map([ diff --git a/test/parallel/test-https-agent-session-eviction.js b/test/parallel/test-https-agent-session-eviction.js index 6f88e81e9ff29d..a3fd362b5c5ae8 100644 --- a/test/parallel/test-https-agent-session-eviction.js +++ b/test/parallel/test-https-agent-session-eviction.js @@ -17,9 +17,12 @@ const options = { key: readKey('agent1-key.pem'), cert: readKey('agent1-cert.pem'), secureOptions: SSL_OP_NO_TICKET, - ciphers: 'RSA@SECLEVEL=0' }; +if (!process.features.openssl_is_boringssl) { + options.ciphers = 'RSA@SECLEVEL=0'; +} + // Create TLS1.2 server https.createServer(options, function(req, res) { res.writeHead(200, { 'Connection': 'close' }); diff --git a/test/parallel/test-inspector-emit-protocol-event.js b/test/parallel/test-inspector-emit-protocol-event.js index e17e994ee520a3..b539831f4399b6 100644 --- a/test/parallel/test-inspector-emit-protocol-event.js +++ b/test/parallel/test-inspector-emit-protocol-event.js @@ -42,7 +42,9 @@ const EXPECTED_EVENTS = { url: 'https://nodejs.org/en', status: 200, statusText: '', - headers: { host: 'nodejs.org' } + headers: { host: 'nodejs.org' }, + mimeType: 'text/html', + charset: 'utf-8' } }, expected: { @@ -53,10 +55,17 @@ const EXPECTED_EVENTS = { url: 'https://nodejs.org/en', status: 200, statusText: '', - headers: { host: 'nodejs.org' } + headers: { host: 'nodejs.org' }, + mimeType: 'text/html', + charset: 'utf-8' } } }, + { + name: 'dataReceived', + // Network.dataReceived is buffered until Network.streamResourceContent is invoked. + skip: true, + }, { name: 'loadingFinished', params: { @@ -81,8 +90,8 @@ for (const [domain, events] of Object.entries(EXPECTED_EVENTS)) { if (!(domain in inspector)) { assert.fail(`Expected domain ${domain} to be present in inspector`); } - const actualEventNames = Object.keys(inspector[domain]); - const expectedEventNames = events.map((event) => event.name); + const actualEventNames = Object.keys(inspector[domain]).sort(); + const expectedEventNames = events.map((event) => event.name).sort(); assert.deepStrictEqual(actualEventNames, expectedEventNames, `Expected ${domain} to have events ${expectedEventNames}, but got ${actualEventNames}`); } @@ -105,6 +114,9 @@ const runAsyncTest = async () => { await session.post('Network.enable'); for (const [domain, events] of Object.entries(EXPECTED_EVENTS)) { for (const event of events) { + if (event.skip) { + continue; + } session.on(`${domain}.${event.name}`, common.mustCall(({ params }) => { if (event.name === 'requestWillBeSent') { // Initiator is automatically captured and contains caller info. diff --git a/test/parallel/test-inspector-network-content-type.js b/test/parallel/test-inspector-network-content-type.js new file mode 100644 index 00000000000000..c8744e521fc5ec --- /dev/null +++ b/test/parallel/test-inspector-network-content-type.js @@ -0,0 +1,170 @@ +// Flags: --inspect=0 --experimental-network-inspection +'use strict'; +const common = require('../common'); + +common.skipIfInspectorDisabled(); + +const assert = require('node:assert'); +const http = require('node:http'); +const inspector = require('node:inspector/promises'); + +const testNetworkInspection = async (session, port, assert) => { + let assertPromise = assert(session); + fetch(`http://127.0.0.1:${port}/hello-world`).then(common.mustCall()); + await assertPromise; + session.removeAllListeners(); + assertPromise = assert(session); + new Promise((resolve, reject) => { + const req = http.get( + { + host: '127.0.0.1', + port, + path: '/hello-world', + }, + common.mustCall((res) => { + res.on('data', () => {}); + res.on('end', () => {}); + resolve(res); + }) + ); + req.on('error', reject); + }); + await assertPromise; + session.removeAllListeners(); +}; + +const test = (handleRequest, testSessionFunc) => new Promise((resolve) => { + const session = new inspector.Session(); + session.connect(); + const httpServer = http.createServer(handleRequest); + httpServer.listen(0, async () => { + try { + await session.post('Network.enable'); + await testNetworkInspection( + session, + httpServer.address().port, + testSessionFunc + ); + await session.post('Network.disable'); + } catch (err) { + assert.fail(err); + } finally { + await session.disconnect(); + await httpServer.close(); + await inspector.close(); + resolve(); + } + }); +}); + +(async () => { + await test( + (req, res) => { + res.setHeader('Content-Type', 'text/plain; charset=utf-8'); + res.writeHead(200); + res.end('hello world\n'); + }, + common.mustCall( + (session) => + new Promise((resolve) => { + session.on( + 'Network.responseReceived', + common.mustCall(({ params }) => { + assert.strictEqual(params.response.mimeType, 'text/plain'); + assert.strictEqual(params.response.charset, 'utf-8'); + }) + ); + session.on( + 'Network.loadingFinished', + common.mustCall(({ params }) => { + assert.ok(params.requestId.startsWith('node-network-event-')); + assert.strictEqual(typeof params.timestamp, 'number'); + resolve(); + }) + ); + }), + 2 + ) + ); + + await test( + (req, res) => { + res.writeHead(200, {}); + res.end('hello world\n'); + }, + common.mustCall((session) => + new Promise((resolve) => { + session.on( + 'Network.responseReceived', + common.mustCall(({ params }) => { + assert.strictEqual(params.response.mimeType, ''); + assert.strictEqual(params.response.charset, ''); + }) + ); + session.on( + 'Network.loadingFinished', + common.mustCall(({ params }) => { + assert.ok(params.requestId.startsWith('node-network-event-')); + assert.strictEqual(typeof params.timestamp, 'number'); + resolve(); + }) + ); + }), 2 + ) + ); + + await test( + (req, res) => { + res.setHeader('Content-Type', 'invalid content-type'); + res.writeHead(200); + res.end('hello world\n'); + }, + common.mustCall((session) => + new Promise((resolve) => { + session.on( + 'Network.responseReceived', + common.mustCall(({ params }) => { + assert.strictEqual(params.response.mimeType, ''); + assert.strictEqual(params.response.charset, ''); + }) + ); + session.on( + 'Network.loadingFinished', + common.mustCall(({ params }) => { + assert.ok(params.requestId.startsWith('node-network-event-')); + assert.strictEqual(typeof params.timestamp, 'number'); + resolve(); + }) + ); + }), 2 + ) + ); + + await test( + (req, res) => { + res.setHeader('Content-Type', 'text/plain'); + res.writeHead(200); + res.end('hello world\n'); + }, + common.mustCall((session) => + new Promise((resolve) => { + session.on( + 'Network.responseReceived', + common.mustCall(({ params }) => { + assert.strictEqual(params.response.mimeType, 'text/plain'); + assert.strictEqual(params.response.charset, ''); + }) + ); + session.on( + 'Network.loadingFinished', + common.mustCall(({ params }) => { + assert.ok(params.requestId.startsWith('node-network-event-')); + assert.strictEqual(typeof params.timestamp, 'number'); + resolve(); + }) + ); + }), 2 + ) + ); + +})().then(common.mustCall()); diff --git a/test/parallel/test-inspector-network-data-received.js b/test/parallel/test-inspector-network-data-received.js new file mode 100644 index 00000000000000..fde584c885567a --- /dev/null +++ b/test/parallel/test-inspector-network-data-received.js @@ -0,0 +1,146 @@ +// Flags: --inspect=0 --experimental-network-inspection +'use strict'; +const common = require('../common'); + +common.skipIfInspectorDisabled(); + +const inspector = require('node:inspector/promises'); +const { Network } = require('node:inspector'); +const test = require('node:test'); +const assert = require('node:assert'); +const { waitUntil } = require('../common/inspector-helper'); +const { setTimeout } = require('node:timers/promises'); + +const session = new inspector.Session(); +session.connect(); +session.post('Network.enable'); + +async function triggerNetworkEvents(requestId) { + const url = 'https://example.com'; + Network.requestWillBeSent({ + requestId, + timestamp: 1, + wallTime: 1, + request: { + url, + method: 'GET', + headers: { + mKey: 'mValue', + }, + }, + }); + await setTimeout(1); + + Network.responseReceived({ + requestId, + timestamp: 2, + type: 'Fetch', + response: { + url, + status: 200, + statusText: 'OK', + headers: { + mKey: 'mValue', + }, + }, + }); + await setTimeout(1); + + const chunk1 = Buffer.from('Hello, '); + Network.dataReceived({ + requestId, + timestamp: 3, + dataLength: chunk1.byteLength, + encodedDataLength: chunk1.byteLength, + data: chunk1, + }); + await setTimeout(1); + + const chunk2 = Buffer.from('world'); + Network.dataReceived({ + requestId, + timestamp: 4, + dataLength: chunk2.byteLength, + encodedDataLength: chunk2.byteLength, + data: chunk2, + }); + await setTimeout(1); + + Network.loadingFinished({ + requestId, + timestamp: 5, + }); +} + +test('should stream Network.dataReceived with data chunks', async () => { + session.removeAllListeners(); + + const requestId = 'my-req-id-1'; + const chunks = []; + let totalDataLength = 0; + session.on('Network.requestWillBeSent', common.mustCall(({ params }) => { + assert.strictEqual(params.requestId, requestId); + })); + const responseReceivedFuture = waitUntil(session, 'Network.responseReceived') + .then(async ([{ params }]) => { + assert.strictEqual(params.requestId, requestId); + const { bufferedData } = await session.post('Network.streamResourceContent', { + requestId, + }); + const data = Buffer.from(bufferedData, 'base64'); + totalDataLength += data.byteLength; + chunks.push(data); + }); + const loadingFinishedFuture = waitUntil(session, 'Network.loadingFinished') + .then(([{ params }]) => { + assert.strictEqual(params.requestId, requestId); + }); + session.on('Network.dataReceived', ({ params }) => { + assert.strictEqual(params.requestId, requestId); + totalDataLength += params.dataLength; + chunks.push(Buffer.from(params.data, 'base64')); + }); + + await triggerNetworkEvents(requestId); + await responseReceivedFuture; + await loadingFinishedFuture; + + const data = Buffer.concat(chunks); + assert.strictEqual(data.byteLength, totalDataLength, data); + assert.strictEqual(data.toString('utf8'), 'Hello, world'); +}); + +test('Network.streamResourceContent should send all buffered chunks', async () => { + session.removeAllListeners(); + + const requestId = 'my-req-id-2'; + session.on('Network.requestWillBeSent', common.mustCall(({ params }) => { + assert.strictEqual(params.requestId, requestId); + })); + session.on('Network.responseReceived', common.mustCall(({ params }) => { + assert.strictEqual(params.requestId, requestId); + })); + const loadingFinishedFuture = waitUntil(session, 'Network.loadingFinished') + .then(async ([{ params }]) => { + assert.strictEqual(params.requestId, requestId); + }); + session.on('Network.dataReceived', common.mustNotCall()); + + await triggerNetworkEvents(requestId); + await loadingFinishedFuture; + const { bufferedData } = await session.post('Network.streamResourceContent', { + requestId, + }); + assert.strictEqual(Buffer.from(bufferedData, 'base64').toString('utf8'), 'Hello, world'); +}); + +test('Network.streamResourceContent should reject if request id not found', async () => { + session.removeAllListeners(); + + const requestId = 'unknown-request-id'; + await assert.rejects(session.post('Network.streamResourceContent', { + requestId, + }), { + code: 'ERR_INSPECTOR_COMMAND', + }); +}); diff --git a/test/parallel/test-inspector-network-fetch.js b/test/parallel/test-inspector-network-fetch.js index 88585ab72bac75..cc16667c54a02d 100644 --- a/test/parallel/test-inspector-network-fetch.js +++ b/test/parallel/test-inspector-network-fetch.js @@ -36,6 +36,7 @@ const setResponseHeaders = (res) => { res.setHeader('etag', 12345); res.setHeader('Set-Cookie', ['key1=value1', 'key2=value2']); res.setHeader('x-header2', ['value1', 'value2']); + res.setHeader('Content-Type', 'text/plain; charset=utf-8'); }; const handleRequest = (req, res) => { @@ -101,6 +102,8 @@ const testHttpGet = () => new Promise((resolve, reject) => { assert.strictEqual(params.response.headers.etag, '12345'); assert.strictEqual(params.response.headers['Set-Cookie'], 'key1=value1\nkey2=value2'); assert.strictEqual(params.response.headers['x-header2'], 'value1, value2'); + assert.strictEqual(params.response.mimeType, 'text/plain'); + assert.strictEqual(params.response.charset, 'utf-8'); })); session.on('Network.loadingFinished', common.mustCall(({ params }) => { assert.ok(params.requestId.startsWith('node-network-event-')); @@ -138,6 +141,8 @@ const testHttpsGet = () => new Promise((resolve, reject) => { assert.strictEqual(params.response.headers.etag, '12345'); assert.strictEqual(params.response.headers['Set-Cookie'], 'key1=value1\nkey2=value2'); assert.strictEqual(params.response.headers['x-header2'], 'value1, value2'); + assert.strictEqual(params.response.mimeType, 'text/plain'); + assert.strictEqual(params.response.charset, 'utf-8'); })); session.on('Network.loadingFinished', common.mustCall(({ params }) => { assert.ok(params.requestId.startsWith('node-network-event-')); diff --git a/test/parallel/test-inspector-network-http.js b/test/parallel/test-inspector-network-http.js index a02329891e1208..1dd4a65fc0dd72 100644 --- a/test/parallel/test-inspector-network-http.js +++ b/test/parallel/test-inspector-network-http.js @@ -27,6 +27,7 @@ const setResponseHeaders = (res) => { res.setHeader('etag', 12345); res.setHeader('Set-Cookie', ['key1=value1', 'key2=value2']); res.setHeader('x-header2', ['value1', 'value2']); + res.setHeader('Content-Type', 'text/plain; charset=utf-8'); }; const kTimeout = 1000; @@ -106,6 +107,8 @@ function verifyResponseReceived({ method, params }, expect) { assert.strictEqual(params.response.headers.etag, '12345'); assert.strictEqual(params.response.headers['set-cookie'], 'key1=value1\nkey2=value2'); assert.strictEqual(params.response.headers['x-header2'], 'value1, value2'); + assert.strictEqual(params.response.mimeType, 'text/plain'); + assert.strictEqual(params.response.charset, 'utf-8'); return params; } diff --git a/test/parallel/test-inspector-worker-target.js b/test/parallel/test-inspector-worker-target.js new file mode 100644 index 00000000000000..e5d2a0c2039712 --- /dev/null +++ b/test/parallel/test-inspector-worker-target.js @@ -0,0 +1,75 @@ +'use strict'; + +const common = require('../common'); +const fixtures = require('../common/fixtures'); + +common.skipIfInspectorDisabled(); + +const { NodeInstance } = require('../common/inspector-helper.js'); + +async function setupInspector(session, sessionId = undefined) { + await session.send({ method: 'NodeRuntime.enable', sessionId }); + await session.waitForNotification('NodeRuntime.waitingForDebugger'); + await session.send({ method: 'Runtime.enable', sessionId }); + await session.send({ method: 'Debugger.enable', sessionId }); + await session.send({ method: 'Runtime.runIfWaitingForDebugger', sessionId }); + await session.send({ method: 'NodeRuntime.disable', sessionId }); + await session.waitForNotification((notification) => { + return notification.method === 'Debugger.scriptParsed' && + notification.params.url === 'node:internal/bootstrap/realm' && + notification.sessionId === sessionId; + }); +} + +async function test(isSetAutoAttachBeforeExecution) { + const child = new NodeInstance(['--inspect-brk=0', '--experimental-worker-inspection'], + '', + fixtures.path('inspect-worker/index.js') + ); + + + const session = await child.connectInspectorSession(); + await setupInspector(session); + + if (isSetAutoAttachBeforeExecution) { + await session.send({ method: 'Target.setAutoAttach', params: { autoAttach: true, waitForDebuggerOnStart: true } }); + } + await session.waitForNotification('Debugger.paused'); + await session.send({ method: 'Debugger.resume' }); + + const sessionId = '1'; + await session.waitForNotification('Target.targetCreated'); + + if (!isSetAutoAttachBeforeExecution) { + await session.send({ method: 'Target.setAutoAttach', params: { autoAttach: true, waitForDebuggerOnStart: true } }); + } + await session.waitForNotification((notification) => { + return notification.method === 'Target.attachedToTarget' && + notification.params.sessionId === sessionId; + }); + await setupInspector(session, sessionId); + await session.waitForNotification('Debugger.paused'); + await session.send({ method: 'Debugger.resume', sessionId }); + await session.waitForDisconnect(); +} + +test(true).then(common.mustCall()); +test(false).then(common.mustCall()); + +function withPermissionOptionTest() { + const permissionErrorThrow = common.mustCall(); + const child = new NodeInstance(['--inspect-brk=0', '--experimental-worker-inspection', '--permission'], + '', + fixtures.path('inspect-worker/index.js'), + { + log: (_, msg) => { + if (msg.includes('Access to this API has been restricted')) { + permissionErrorThrow(); + } + }, + error: () => {}, + } + ); + child.connectInspectorSession(); +} +withPermissionOptionTest(); diff --git a/test/parallel/test-internal-util-helpers.js b/test/parallel/test-internal-util-helpers.js index bf60cff9bda4be..01e99d52420d40 100644 --- a/test/parallel/test-internal-util-helpers.js +++ b/test/parallel/test-internal-util-helpers.js @@ -4,7 +4,7 @@ require('../common'); const assert = require('assert'); const { types } = require('util'); -const { isError } = require('internal/util'); +const { assignFunctionName, isError } = require('internal/util'); const vm = require('vm'); // Special cased errors. Test the internal function which is used in @@ -35,3 +35,30 @@ const vm = require('vm'); assert(!(differentRealmErr instanceof Error)); assert(isError(differentRealmErr)); } + +{ + const nameMap = new Map([ + [ 'meaningfulName', 'meaningfulName' ], + [ '', '' ], + [ Symbol.asyncIterator, '[Symbol.asyncIterator]' ], + [ Symbol('notWellKnownSymbol'), '[notWellKnownSymbol]' ], + ]); + for (const fn of [ + () => {}, + function() {}, + function value() {}, + ({ value() {} }).value, + new Function(), + Function(), + function() {}.bind(null), + class {}, + class value {}, + ]) { + for (const [ stringOrSymbol, expectedName ] of nameMap) { + const namedFn = assignFunctionName(stringOrSymbol, fn); + assert.strictEqual(fn, namedFn); + assert.strictEqual(namedFn.name, expectedName); + assert.strictEqual(namedFn.bind(null).name, `bound ${expectedName}`); + } + } +} diff --git a/test/parallel/test-node-output-sourcemaps.mjs b/test/parallel/test-node-output-sourcemaps.mjs index 29cc5eb711f176..81c36934ba0f3e 100644 --- a/test/parallel/test-node-output-sourcemaps.mjs +++ b/test/parallel/test-node-output-sourcemaps.mjs @@ -1,29 +1,17 @@ -import * as common from '../common/index.mjs'; +import '../common/index.mjs'; import * as fixtures from '../common/fixtures.mjs'; import * as snapshot from '../common/assertSnapshot.js'; -import * as path from 'node:path'; import { describe, it } from 'node:test'; describe('sourcemaps output', { concurrency: !process.env.TEST_PARALLEL }, () => { - function normalize(str) { - const result = str - .replaceAll(snapshot.replaceWindowsPaths(process.cwd()), '') - .replaceAll('//', '*') - .replaceAll('/Users/bencoe/oss/coffee-script-test', '') - .replaceAll(/\/(\w)/g, '*$1') - .replaceAll('*test*', '*') - .replaceAll('*fixtures*source-map*', '*') - .replaceAll(/(\W+).*node:.*/g, '$1*'); - if (common.isWindows) { - const currentDeviceLetter = path.parse(process.cwd()).root.substring(0, 1).toLowerCase(); - const regex = new RegExp(`${currentDeviceLetter}:/?`, 'gi'); - return result.replaceAll(regex, ''); - } - return result; - } const defaultTransform = snapshot - .transform(snapshot.replaceWindowsLineEndings, snapshot.replaceWindowsPaths, - normalize, snapshot.replaceNodeVersion); + .transform( + snapshot.replaceWindowsLineEndings, + snapshot.transformProjectRoot('*'), + snapshot.replaceWindowsPaths, + snapshot.replaceInternalStackTrace, + snapshot.replaceNodeVersion + ); const tests = [ { name: 'source-map/output/source_map_disabled_by_api.js' }, diff --git a/test/parallel/test-os-fast.js b/test/parallel/test-os-fast.js new file mode 100644 index 00000000000000..786d2f4a7d90b1 --- /dev/null +++ b/test/parallel/test-os-fast.js @@ -0,0 +1,30 @@ +// Flags: --expose-internals --no-warnings --allow-natives-syntax +'use strict'; + +const common = require('../common'); +const assert = require('assert'); +const { + totalmem, + freemem, + availableParallelism, +} = require('os'); + +const { internalBinding } = require('internal/test/binding'); + +function testFastOs() { + assert.strictEqual(typeof totalmem(), 'number'); + assert.strictEqual(typeof freemem(), 'number'); + assert.strictEqual(typeof availableParallelism(), 'number'); +} + +eval('%PrepareFunctionForOptimization(testFastOs)'); +testFastOs(); +eval('%OptimizeFunctionOnNextCall(testFastOs)'); +testFastOs(); + +if (common.isDebug) { + const { getV8FastApiCallCount } = internalBinding('debug'); + assert.strictEqual(getV8FastApiCallCount('os.totalmem'), 1); + assert.strictEqual(getV8FastApiCallCount('os.freemem'), 1); + assert.strictEqual(getV8FastApiCallCount('os.availableParallelism'), 1); +} diff --git a/test/parallel/test-path-resolve.js b/test/parallel/test-path-resolve.js index 3fc9b2e3abd90a..fc704b815764b0 100644 --- a/test/parallel/test-path-resolve.js +++ b/test/parallel/test-path-resolve.js @@ -24,6 +24,8 @@ const resolveTests = [ [['c:/ignore', 'd:\\a/b\\c/d', '\\e.exe'], 'd:\\e.exe'], [['c:/ignore', 'c:/some/file'], 'c:\\some\\file'], [['d:/ignore', 'd:some/dir//'], 'd:\\ignore\\some\\dir'], + [[], process.cwd()], + [[''], process.cwd()], [['.'], process.cwd()], [['//server/share', '..', 'relative\\'], '\\\\server\\share\\relative'], [['c:/', '//'], 'c:\\'], @@ -40,6 +42,8 @@ const resolveTests = [ [[['/var/lib', '../', 'file/'], '/var/file'], [['/var/lib', '/../', 'file/'], '/file'], [['a/b/c/', '../../..'], posixyCwd], + [[], posixyCwd], + [[''], posixyCwd], [['.'], posixyCwd], [['/some/dir', '.', '/absolute/'], '/absolute'], [['/foo/tmp.3/', '../tmp.3/cycles/root.js'], '/foo/tmp.3/cycles/root.js'], diff --git a/test/parallel/test-permission-fs-read-entrypoint.js b/test/parallel/test-permission-fs-read-entrypoint.js new file mode 100644 index 00000000000000..631c793e1357f2 --- /dev/null +++ b/test/parallel/test-permission-fs-read-entrypoint.js @@ -0,0 +1,38 @@ +// Flags: --permission --allow-fs-read=* --allow-fs-write=* --allow-child-process +'use strict'; + +const common = require('../common'); +const { isMainThread } = require('worker_threads'); + +if (!isMainThread) { + common.skip('This test only works on a main thread'); +} + +if (!common.hasCrypto) { + common.skip('no crypto'); +} + +const assert = require('assert'); +const fixtures = require('../common/fixtures'); +const { spawnSync } = require('child_process'); + +const file = fixtures.path('permission', 'hello-world.js'); +const simpleLoader = fixtures.path('permission', 'simple-loader.js'); +const fsReadLoader = fixtures.path('permission', 'fs-read-loader.js'); + +[ + '', + simpleLoader, + fsReadLoader, +].forEach((arg0) => { + const { status, stderr } = spawnSync( + process.execPath, + [ + arg0 !== '' ? '-r' : '', + arg0, + '--permission', + file, + ], + ); + assert.strictEqual(status, 0, `${arg0} Error: ${stderr.toString()}`); +}); diff --git a/test/parallel/test-permission-fs-read.js b/test/parallel/test-permission-fs-read.js index b719207bdbd820..2388470a0b42ba 100644 --- a/test/parallel/test-permission-fs-read.js +++ b/test/parallel/test-permission-fs-read.js @@ -32,7 +32,11 @@ const commonPath = path.join(__filename, '../../common'); const { status, stderr } = spawnSync( process.execPath, [ - '--permission', `--allow-fs-read=${file}`, `--allow-fs-read=${commonPathWildcard}`, file, + '--permission', + // Do not uncomment this line + // `--allow-fs-read=${file}`, + `--allow-fs-read=${commonPathWildcard}`, + file, ], { env: { diff --git a/test/parallel/test-permission-sqlite-load-extension.js b/test/parallel/test-permission-sqlite-load-extension.js index 1e6f7426ed9400..def6f3d12699d0 100644 --- a/test/parallel/test-permission-sqlite-load-extension.js +++ b/test/parallel/test-permission-sqlite-load-extension.js @@ -1,5 +1,6 @@ 'use strict'; const common = require('../common'); +common.skipIfSQLiteMissing(); const assert = require('node:assert'); const code = `const sqlite = require('node:sqlite'); diff --git a/test/parallel/test-process-features.js b/test/parallel/test-process-features.js index 19b1c3a4f480e1..e4365b656df2f5 100644 --- a/test/parallel/test-process-features.js +++ b/test/parallel/test-process-features.js @@ -9,6 +9,7 @@ const expectedKeys = new Map([ ['debug', ['boolean']], ['uv', ['boolean']], ['ipv6', ['boolean']], + ['openssl_is_boringssl', ['boolean']], ['tls_alpn', ['boolean']], ['tls_sni', ['boolean']], ['tls_ocsp', ['boolean']], diff --git a/test/parallel/test-process-get-builtin.mjs b/test/parallel/test-process-get-builtin.mjs index f22cf8a1a4728b..03165c4b2e66a4 100644 --- a/test/parallel/test-process-get-builtin.mjs +++ b/test/parallel/test-process-get-builtin.mjs @@ -1,4 +1,4 @@ -import { hasCrypto, hasIntl } from '../common/index.mjs'; +import { hasCrypto, hasIntl, hasSQLite } from '../common/index.mjs'; import assert from 'node:assert'; import { builtinModules } from 'node:module'; import { isMainThread } from 'node:worker_threads'; @@ -37,6 +37,10 @@ if (!hasIntl) { publicBuiltins.delete('trace_events'); } +if (!hasSQLite) { + publicBuiltins.delete('node:sqlite'); +} + for (const id of publicBuiltins) { assert.strictEqual(process.getBuiltinModule(id), require(id)); } diff --git a/test/parallel/test-process-versions.js b/test/parallel/test-process-versions.js index c22981afa36f52..82b08567993a4a 100644 --- a/test/parallel/test-process-versions.js +++ b/test/parallel/test-process-versions.js @@ -21,12 +21,12 @@ const expected_keys = [ 'acorn', 'simdjson', 'simdutf', - 'sqlite', 'ada', 'cjs_module_lexer', 'nbytes', ]; + const hasUndici = process.config.variables.node_builtin_shareable_builtins.includes('deps/undici/undici.js'); const hasAmaro = process.config.variables.node_builtin_shareable_builtins.includes('deps/amaro/dist/index.js'); @@ -56,6 +56,10 @@ if (common.hasIntl) { expected_keys.push('unicode'); } +if (common.hasSQLite) { + expected_keys.push('sqlite'); +} + expected_keys.sort(); expected_keys.unshift('node'); diff --git a/test/parallel/test-repl-null-thrown.js b/test/parallel/test-repl-null-thrown.js index 0ed4a05fd5de55..2d28aa2d820ac2 100644 --- a/test/parallel/test-repl-null-thrown.js +++ b/test/parallel/test-repl-null-thrown.js @@ -19,6 +19,5 @@ replserver.emit('line', 'process.nextTick(() => { throw null; })'); replserver.emit('line', '.exit'); setTimeout(() => { - console.log(text); assert(text.includes('Uncaught null')); }, 0); diff --git a/test/parallel/test-runner-coverage-thresholds.js b/test/parallel/test-runner-coverage-thresholds.js index c1b64cb06a83ff..9a13394f6f631a 100644 --- a/test/parallel/test-runner-coverage-thresholds.js +++ b/test/parallel/test-runner-coverage-thresholds.js @@ -88,6 +88,26 @@ for (const coverage of coverages) { assert(!findCoverageFileForPid(result.pid)); }); + test(`test failing ${coverage.flag} with red color`, () => { + const result = spawnSync(process.execPath, [ + '--test', + '--experimental-test-coverage', + '--test-coverage-exclude=!test/**', + `${coverage.flag}=99`, + '--test-reporter', 'spec', + fixture, + ], { + env: { ...process.env, FORCE_COLOR: '3' }, + }); + + const stdout = result.stdout.toString(); + // eslint-disable-next-line no-control-regex + const redColorRegex = /\u001b\[31mℹ Error: \d{2}\.\d{2}% \w+ coverage does not meet threshold of 99%/; + assert.match(stdout, redColorRegex, 'Expected red color code not found in diagnostic message'); + assert.strictEqual(result.status, 1); + assert(!findCoverageFileForPid(result.pid)); + }); + test(`test failing ${coverage.flag}`, () => { const result = spawnSync(process.execPath, [ '--test', diff --git a/test/parallel/test-runner-module-mocking.js b/test/parallel/test-runner-module-mocking.js index 7f84e9df54eaa8..5d5588351621b8 100644 --- a/test/parallel/test-runner-module-mocking.js +++ b/test/parallel/test-runner-module-mocking.js @@ -365,6 +365,34 @@ test('ESM mocking with namedExports option', async (t) => { }); }); +test('JSON mocking', async (t) => { + await t.test('with defaultExport', async (t) => { + const fixturePath = fixtures.path('module-mocking', 'basic.json'); + const fixture = pathToFileURL(fixturePath); + const { default: original } = await import(fixture, { with: { type: 'json' } }); + + assert.deepStrictEqual(original, { foo: 'bar' }); + + const defaultExport = { qux: 'zed' }; + + t.mock.module(fixture, { defaultExport }); + + const { default: mocked } = await import(fixture, { with: { type: 'json' } }); + + assert.deepStrictEqual(mocked, defaultExport); + }); + + await t.test('throws without appropriate import attributes', async (t) => { + const fixturePath = fixtures.path('module-mocking', 'basic.json'); + const fixture = pathToFileURL(fixturePath); + + const defaultExport = { qux: 'zed' }; + t.mock.module(fixture, { defaultExport }); + + await assert.rejects(() => import(fixture), /import attribute/); + }); +}); + test('modules cannot be mocked multiple times at once', async (t) => { await t.test('CJS', async (t) => { const fixture = fixtures.path('module-mocking', 'basic-cjs.js'); diff --git a/test/parallel/test-runner-output.mjs b/test/parallel/test-runner-output.mjs index c2ea8eddc02bbc..056b5436053e74 100644 --- a/test/parallel/test-runner-output.mjs +++ b/test/parallel/test-runner-output.mjs @@ -70,7 +70,7 @@ const defaultTransform = snapshot.transform( snapshot.replaceWindowsLineEndings, snapshot.replaceStackTrace, removeWindowsPathEscaping, - snapshot.replaceFullPaths, + snapshot.transformProjectRoot(), snapshot.replaceWindowsPaths, replaceTestDuration, replaceTestLocationLine, @@ -90,7 +90,7 @@ const junitTransform = snapshot.transform( const lcovTransform = snapshot.transform( snapshot.replaceWindowsLineEndings, snapshot.replaceStackTrace, - snapshot.replaceFullPaths, + snapshot.transformProjectRoot(), snapshot.replaceWindowsPaths, pickTestFileFromLcov ); @@ -302,6 +302,15 @@ const tests = [ flags: ['--test-reporter=tap', '--test-coverage-exclude=../output/**'], cwd: fixtures.path('test-runner/coverage-snap'), } : false, + process.features.inspector ? { + name: 'test-runner/output/typescript-coverage.mts', + flags: ['--disable-warning=ExperimentalWarning', + '--test-reporter=tap', + '--experimental-transform-types', + '--experimental-test-module-mocks', + '--experimental-test-coverage', + '--test-coverage-exclude=!test/**'] + } : false, ] .filter(Boolean) .map(({ flags, name, tty, transform, cwd }) => ({ diff --git a/test/parallel/test-runner-run.mjs b/test/parallel/test-runner-run.mjs index 0a8e49dfe6a114..39adac01290cc3 100644 --- a/test/parallel/test-runner-run.mjs +++ b/test/parallel/test-runner-run.mjs @@ -33,6 +33,24 @@ describe('require(\'node:test\').run', { concurrency: true }, () => { for await (const _ of stream); }); + it('should emit diagnostic events with level parameter', async () => { + const diagnosticEvents = []; + + const stream = run({ + files: [join(testFixtures, 'coverage.js')], + reporter: 'spec', + }); + + stream.on('test:diagnostic', (event) => { + diagnosticEvents.push(event); + }); + // eslint-disable-next-line no-unused-vars + for await (const _ of stream); + assert(diagnosticEvents.length > 0, 'No diagnostic events were emitted'); + const infoEvent = diagnosticEvents.find((e) => e.level === 'info'); + assert(infoEvent, 'No diagnostic events with level "info" were emitted'); + }); + const argPrintingFile = join(testFixtures, 'print-arguments.js'); it('should allow custom arguments via execArgv', async () => { const result = await run({ files: [argPrintingFile], execArgv: ['-p', '"Printed"'] }).compose(spec).toArray(); diff --git a/test/parallel/test-source-map-enable.js b/test/parallel/test-source-map-enable.js index 64f4254fcddbc6..a41170f17a91d6 100644 --- a/test/parallel/test-source-map-enable.js +++ b/test/parallel/test-source-map-enable.js @@ -273,7 +273,7 @@ function nextdir() { // Does not attempt to apply path resolution logic to absolute URLs // with schemes. // Refs: https://github.com/webpack/webpack/issues/9601 -// Refs: https://sourcemaps.info/spec.html#h.75yo6yoyk7x5 +// Refs: https://tc39.es/ecma426/#sec-sources { const output = spawnSync(process.execPath, [ '--enable-source-maps', diff --git a/test/parallel/test-sqlite-aggregate-function.mjs b/test/parallel/test-sqlite-aggregate-function.mjs index acc4ad90f97979..050705c771e6af 100644 --- a/test/parallel/test-sqlite-aggregate-function.mjs +++ b/test/parallel/test-sqlite-aggregate-function.mjs @@ -1,6 +1,7 @@ -import '../common/index.mjs'; -import { DatabaseSync } from 'node:sqlite'; +import { skipIfSQLiteMissing } from '../common/index.mjs'; import { describe, test } from 'node:test'; +skipIfSQLiteMissing(); +const { DatabaseSync } = await import('node:sqlite'); describe('DatabaseSync.prototype.aggregate()', () => { describe('input validation', () => { @@ -308,6 +309,27 @@ describe('step', () => { }); describe('result', () => { + test('throws if result throws an error', (t) => { + const db = new DatabaseSync(':memory:'); + t.after(() => db.close()); + db.exec('CREATE TABLE data (value INTEGER)'); + db.exec('INSERT INTO data VALUES (1), (2), (3)'); + db.aggregate('sum_int', { + start: 0, + step: (acc, value) => { + return acc + value; + }, + result: () => { + throw new Error('result error'); + }, + }); + t.assert.throws(() => { + db.prepare('SELECT sum_int(value) as result FROM data').get(); + }, { + message: 'result error' + }); + }); + test('executes once when options.inverse is not present', (t) => { const db = new DatabaseSync(':memory:'); t.after(() => db.close()); diff --git a/test/parallel/test-sqlite-backup.mjs b/test/parallel/test-sqlite-backup.mjs index 96c8dd2ead9f44..693a2dcb337871 100644 --- a/test/parallel/test-sqlite-backup.mjs +++ b/test/parallel/test-sqlite-backup.mjs @@ -1,9 +1,10 @@ -import '../common/index.mjs'; +import { skipIfSQLiteMissing } from '../common/index.mjs'; import tmpdir from '../common/tmpdir.js'; import { join } from 'node:path'; -import { backup, DatabaseSync } from 'node:sqlite'; import { describe, test } from 'node:test'; import { writeFileSync } from 'node:fs'; +skipIfSQLiteMissing(); +const { backup, DatabaseSync } = await import('node:sqlite'); let cnt = 0; @@ -234,3 +235,8 @@ test('backup fails when destination cannot be opened', async (t) => { message: 'unable to open database file' }); }); + +test('backup has correct name and length', (t) => { + t.assert.strictEqual(backup.name, 'backup'); + t.assert.strictEqual(backup.length, 2); +}); diff --git a/test/parallel/test-sqlite-custom-functions.js b/test/parallel/test-sqlite-custom-functions.js index b509ebb3d4c76c..d535cda821e10e 100644 --- a/test/parallel/test-sqlite-custom-functions.js +++ b/test/parallel/test-sqlite-custom-functions.js @@ -1,5 +1,6 @@ 'use strict'; -require('../common'); +const { skipIfSQLiteMissing } = require('../common'); +skipIfSQLiteMissing(); const assert = require('node:assert'); const { DatabaseSync } = require('node:sqlite'); const { suite, test } = require('node:test'); diff --git a/test/parallel/test-sqlite-data-types.js b/test/parallel/test-sqlite-data-types.js index 75f1257f4d04b4..590c6d5bdc1e6e 100644 --- a/test/parallel/test-sqlite-data-types.js +++ b/test/parallel/test-sqlite-data-types.js @@ -1,5 +1,6 @@ 'use strict'; -require('../common'); +const { skipIfSQLiteMissing } = require('../common'); +skipIfSQLiteMissing(); const tmpdir = require('../common/tmpdir'); const { join } = require('node:path'); const { DatabaseSync } = require('node:sqlite'); diff --git a/test/parallel/test-sqlite-database-sync-dispose.js b/test/parallel/test-sqlite-database-sync-dispose.js index 6b0dd09102bf01..67a1ab6757b848 100644 --- a/test/parallel/test-sqlite-database-sync-dispose.js +++ b/test/parallel/test-sqlite-database-sync-dispose.js @@ -1,5 +1,6 @@ 'use strict'; -require('../common'); +const { skipIfSQLiteMissing } = require('../common'); +skipIfSQLiteMissing(); const tmpdir = require('../common/tmpdir'); const assert = require('node:assert'); const { join } = require('node:path'); diff --git a/test/parallel/test-sqlite-database-sync.js b/test/parallel/test-sqlite-database-sync.js index 773958cf2700db..b7a6718cd99a34 100644 --- a/test/parallel/test-sqlite-database-sync.js +++ b/test/parallel/test-sqlite-database-sync.js @@ -1,5 +1,6 @@ 'use strict'; -require('../common'); +const { skipIfSQLiteMissing } = require('../common'); +skipIfSQLiteMissing(); const tmpdir = require('../common/tmpdir'); const { existsSync } = require('node:fs'); const { join } = require('node:path'); @@ -163,7 +164,7 @@ suite('DatabaseSync() constructor', () => { db.exec('SELECT "foo";'); }, { code: 'ERR_SQLITE_ERROR', - message: /no such column: "foo"/, + message: /no such column: "?foo"?/, }); }); diff --git a/test/parallel/test-sqlite-named-parameters.js b/test/parallel/test-sqlite-named-parameters.js index c9f71fa452fb93..e1acd0f38fa2f7 100644 --- a/test/parallel/test-sqlite-named-parameters.js +++ b/test/parallel/test-sqlite-named-parameters.js @@ -1,5 +1,6 @@ 'use strict'; -require('../common'); +const { skipIfSQLiteMissing } = require('../common'); +skipIfSQLiteMissing(); const tmpdir = require('../common/tmpdir'); const { join } = require('node:path'); const { DatabaseSync } = require('node:sqlite'); diff --git a/test/parallel/test-sqlite-session.js b/test/parallel/test-sqlite-session.js index 5cba37e337e835..121e27ec3e545e 100644 --- a/test/parallel/test-sqlite-session.js +++ b/test/parallel/test-sqlite-session.js @@ -1,6 +1,7 @@ // Flags: --experimental-sqlite 'use strict'; -require('../common'); +const { skipIfSQLiteMissing } = require('../common'); +skipIfSQLiteMissing(); const { DatabaseSync, constants, diff --git a/test/parallel/test-sqlite-statement-sync-columns.js b/test/parallel/test-sqlite-statement-sync-columns.js index 0d3bf2ed4dd804..a0c3fbd74347de 100644 --- a/test/parallel/test-sqlite-statement-sync-columns.js +++ b/test/parallel/test-sqlite-statement-sync-columns.js @@ -1,5 +1,6 @@ 'use strict'; -require('../common'); +const { skipIfSQLiteMissing } = require('../common'); +skipIfSQLiteMissing(); const assert = require('node:assert'); const { DatabaseSync } = require('node:sqlite'); const { suite, test } = require('node:test'); diff --git a/test/parallel/test-sqlite-statement-sync.js b/test/parallel/test-sqlite-statement-sync.js index 235c50ecec9851..858a1486601763 100644 --- a/test/parallel/test-sqlite-statement-sync.js +++ b/test/parallel/test-sqlite-statement-sync.js @@ -1,6 +1,7 @@ // Flags: --expose-gc 'use strict'; -require('../common'); +const { skipIfSQLiteMissing } = require('../common'); +skipIfSQLiteMissing(); const tmpdir = require('../common/tmpdir'); const { join } = require('node:path'); const { DatabaseSync, StatementSync } = require('node:sqlite'); diff --git a/test/parallel/test-sqlite-timeout.js b/test/parallel/test-sqlite-timeout.js index d4ce828f19b8d7..aa3fdae67607fb 100644 --- a/test/parallel/test-sqlite-timeout.js +++ b/test/parallel/test-sqlite-timeout.js @@ -1,5 +1,6 @@ 'use strict'; -require('../common'); +const { skipIfSQLiteMissing } = require('../common'); +skipIfSQLiteMissing(); const tmpdir = require('../common/tmpdir'); const { join } = require('node:path'); const { DatabaseSync } = require('node:sqlite'); diff --git a/test/parallel/test-sqlite-transactions.js b/test/parallel/test-sqlite-transactions.js index 304d27d3f3c65f..50b47829aca012 100644 --- a/test/parallel/test-sqlite-transactions.js +++ b/test/parallel/test-sqlite-transactions.js @@ -1,5 +1,6 @@ 'use strict'; -require('../common'); +const { skipIfSQLiteMissing } = require('../common'); +skipIfSQLiteMissing(); const tmpdir = require('../common/tmpdir'); const { join } = require('node:path'); const { DatabaseSync } = require('node:sqlite'); diff --git a/test/parallel/test-sqlite-typed-array-and-data-view.js b/test/parallel/test-sqlite-typed-array-and-data-view.js index 1cc75c541b6261..71d7b181a3d75e 100644 --- a/test/parallel/test-sqlite-typed-array-and-data-view.js +++ b/test/parallel/test-sqlite-typed-array-and-data-view.js @@ -1,5 +1,6 @@ 'use strict'; -require('../common'); +const { skipIfSQLiteMissing } = require('../common'); +skipIfSQLiteMissing(); const tmpdir = require('../common/tmpdir'); const { join } = require('node:path'); const { DatabaseSync } = require('node:sqlite'); diff --git a/test/parallel/test-sqlite.js b/test/parallel/test-sqlite.js index 578dd9c03d53c6..717c757c6bfd40 100644 --- a/test/parallel/test-sqlite.js +++ b/test/parallel/test-sqlite.js @@ -1,5 +1,6 @@ 'use strict'; -const { spawnPromisified } = require('../common'); +const { spawnPromisified, skipIfSQLiteMissing } = require('../common'); +skipIfSQLiteMissing(); const tmpdir = require('../common/tmpdir'); const { join } = require('node:path'); const { DatabaseSync, constants } = require('node:sqlite'); diff --git a/test/parallel/test-tls-alert-handling.js b/test/parallel/test-tls-alert-handling.js index cba5bebaa29b6f..7bd42bbe721c4c 100644 --- a/test/parallel/test-tls-alert-handling.js +++ b/test/parallel/test-tls-alert-handling.js @@ -35,16 +35,16 @@ let iter = 0; const errorHandler = common.mustCall((err) => { let expectedErrorCode = 'ERR_SSL_WRONG_VERSION_NUMBER'; - let expectedErrorReason = 'wrong version number'; + let expectedErrorReason = /wrong[\s_]version[\s_]number/i; if (hasOpenSSL(3, 2)) { expectedErrorCode = 'ERR_SSL_PACKET_LENGTH_TOO_LONG'; - expectedErrorReason = 'packet length too long'; + expectedErrorReason = /packet[\s_]length[\s_]too[\s_]long/i; }; assert.strictEqual(err.code, expectedErrorCode); assert.strictEqual(err.library, 'SSL routines'); if (!hasOpenSSL3) assert.strictEqual(err.function, 'ssl3_get_record'); - assert.strictEqual(err.reason, expectedErrorReason); + assert.match(err.reason, expectedErrorReason); errorReceived = true; if (canCloseServer()) server.close(); @@ -98,15 +98,15 @@ function sendBADTLSRecord() { })); client.on('error', common.mustCall((err) => { let expectedErrorCode = 'ERR_SSL_TLSV1_ALERT_PROTOCOL_VERSION'; - let expectedErrorReason = 'tlsv1 alert protocol version'; + let expectedErrorReason = /tlsv1[\s_]alert[\s_]protocol[\s_]version/i; if (hasOpenSSL(3, 2)) { expectedErrorCode = 'ERR_SSL_TLSV1_ALERT_RECORD_OVERFLOW'; - expectedErrorReason = 'tlsv1 alert record overflow'; + expectedErrorReason = /tlsv1[\s_]alert[\s_]record[\s_]overflow/i; } assert.strictEqual(err.code, expectedErrorCode); assert.strictEqual(err.library, 'SSL routines'); if (!hasOpenSSL3) assert.strictEqual(err.function, 'ssl3_read_bytes'); - assert.strictEqual(err.reason, expectedErrorReason); + assert.match(err.reason, expectedErrorReason); })); } diff --git a/test/parallel/test-tls-getprotocol.js b/test/parallel/test-tls-getprotocol.js index b1eab88fd6517e..c28b329ba7b642 100644 --- a/test/parallel/test-tls-getprotocol.js +++ b/test/parallel/test-tls-getprotocol.js @@ -29,11 +29,14 @@ const clientConfigs = [ const serverConfig = { secureProtocol: 'TLS_method', - ciphers: 'RSA@SECLEVEL=0', key: fixtures.readKey('agent2-key.pem'), cert: fixtures.readKey('agent2-cert.pem') }; +if (!process.features.openssl_is_boringssl) { + serverConfig.ciphers = 'RSA@SECLEVEL=0'; +} + const server = tls.createServer(serverConfig, common.mustCall(clientConfigs.length)) .listen(0, common.localhostIPv4, function() { let connected = 0; diff --git a/test/parallel/test-tls-write-error.js b/test/parallel/test-tls-write-error.js index b06f2fa2c53ea7..8a8d820a09cca9 100644 --- a/test/parallel/test-tls-write-error.js +++ b/test/parallel/test-tls-write-error.js @@ -17,9 +17,12 @@ const server_cert = fixtures.readKey('agent1-cert.pem'); const opts = { key: server_key, cert: server_cert, - ciphers: 'ALL@SECLEVEL=0' }; +if (!process.features.openssl_is_boringssl) { + opts.ciphers = 'ALL@SECLEVEL=0'; +} + const server = https.createServer(opts, (req, res) => { res.write('hello'); }).listen(0, common.mustCall(() => { diff --git a/test/parallel/test-util-promisify-custom-names.mjs b/test/parallel/test-util-promisify-custom-names.mjs index 3ff05d907b5060..3540d20e262e0c 100644 --- a/test/parallel/test-util-promisify-custom-names.mjs +++ b/test/parallel/test-util-promisify-custom-names.mjs @@ -1,4 +1,4 @@ -import '../common/index.mjs'; +import { hasCrypto } from '../common/index.mjs'; import assert from 'node:assert'; import { promisify } from 'node:util'; @@ -9,6 +9,7 @@ import fs from 'node:fs'; import readline from 'node:readline'; import stream from 'node:stream'; import timers from 'node:timers'; +import child_process from 'node:child_process'; assert.strictEqual( @@ -38,3 +39,20 @@ assert.strictEqual( promisify(timers.setTimeout).name, 'setTimeout' ); + +assert.strictEqual( + promisify(child_process.exec).name, + 'exec' +); +assert.strictEqual( + promisify(child_process.execFile).name, + 'execFile' +); + +if (hasCrypto) { + const http2 = await import('node:http2'); + assert.strictEqual( + promisify(http2.connect).name, + 'connect' + ); +} diff --git a/test/parallel/test-util-styletext.js b/test/parallel/test-util-styletext.js index 68c31eef2e07c8..df2334651cc869 100644 --- a/test/parallel/test-util-styletext.js +++ b/test/parallel/test-util-styletext.js @@ -75,6 +75,8 @@ assert.strictEqual( styled, ); +assert.strictEqual(util.styleText('none', 'test'), 'test'); + const fd = common.getTTYfd(); if (fd !== -1) { const writeStream = new WriteStream(fd); diff --git a/test/parallel/test-vm-module-dynamic-import-promise.js b/test/parallel/test-vm-module-dynamic-import-promise.js new file mode 100644 index 00000000000000..63493212cd3585 --- /dev/null +++ b/test/parallel/test-vm-module-dynamic-import-promise.js @@ -0,0 +1,135 @@ +// Flags: --experimental-vm-modules +'use strict'; + +const common = require('../common'); + +const assert = require('assert'); +const { createContext, Script, SourceTextModule } = require('vm'); + +// Verifies that a `import` call returns a promise created in the context +// where the `import` was called, not the context of `importModuleDynamically` +// callback. + +async function testScript() { + const ctx = createContext(); + + const mod1 = new SourceTextModule('export const a = 1;', { + context: ctx, + }); + // No import statements, so must not link statically. + await mod1.link(common.mustNotCall()); + + const script2 = new Script(` + const promise = import("mod1"); + if (Object.getPrototypeOf(promise) !== Promise.prototype) { + throw new Error('Expected promise to be created in the current context'); + } + globalThis.__result = promise; + `, { + importModuleDynamically: common.mustCall((specifier, referrer) => { + assert.strictEqual(specifier, 'mod1'); + assert.strictEqual(referrer, script2); + return mod1; + }), + }); + script2.runInContext(ctx); + + // Wait for the promise to resolve. + await ctx.__result; +} + +async function testScriptImportFailed() { + const ctx = createContext(); + + const mod1 = new SourceTextModule('export const a = 1;', { + context: ctx, + }); + // No import statements, so must not link statically. + await mod1.link(common.mustNotCall()); + + const err = new Error('import failed'); + const script2 = new Script(` + const promise = import("mod1"); + if (Object.getPrototypeOf(promise) !== Promise.prototype) { + throw new Error('Expected promise to be created in the current context'); + } + globalThis.__result = promise; + `, { + importModuleDynamically: common.mustCall((specifier, referrer) => { + throw err; + }), + }); + script2.runInContext(ctx); + + // Wait for the promise to reject. + await assert.rejects(ctx.__result, err); +} + +async function testModule() { + const ctx = createContext(); + + const mod1 = new SourceTextModule('export const a = 1;', { + context: ctx, + }); + // No import statements, so must not link statically. + await mod1.link(common.mustNotCall()); + + const mod2 = new SourceTextModule(` + const promise = import("mod1"); + if (Object.getPrototypeOf(promise) !== Promise.prototype) { + throw new Error('Expected promise to be created in the current context'); + } + await promise; + `, { + context: ctx, + importModuleDynamically: common.mustCall((specifier, referrer) => { + assert.strictEqual(specifier, 'mod1'); + assert.strictEqual(referrer, mod2); + return mod1; + }), + }); + // No import statements, so must not link statically. + await mod2.link(common.mustNotCall()); + await mod2.evaluate(); +} + +async function testModuleImportFailed() { + const ctx = createContext(); + + const mod1 = new SourceTextModule('export const a = 1;', { + context: ctx, + }); + // No import statements, so must not link statically. + await mod1.link(common.mustNotCall()); + + const err = new Error('import failed'); + ctx.__err = err; + const mod2 = new SourceTextModule(` + const promise = import("mod1"); + if (Object.getPrototypeOf(promise) !== Promise.prototype) { + throw new Error('Expected promise to be created in the current context'); + } + await promise.then(() => { + throw new Error('Expected promise to be rejected'); + }, (e) => { + if (e !== globalThis.__err) { + throw new Error('Expected promise to be rejected with "import failed"'); + } + }); + `, { + context: ctx, + importModuleDynamically: common.mustCall((specifier, referrer) => { + throw err; + }), + }); + // No import statements, so must not link statically. + await mod2.link(common.mustNotCall()); + await mod2.evaluate(); +} + +Promise.all([ + testScript(), + testScriptImportFailed(), + testModule(), + testModuleImportFailed(), +]).then(common.mustCall()); diff --git a/test/parallel/test-webcrypto-derivebits.js b/test/parallel/test-webcrypto-derivebits.js index eb09bc24f0cb82..0db467b852283a 100644 --- a/test/parallel/test-webcrypto-derivebits.js +++ b/test/parallel/test-webcrypto-derivebits.js @@ -123,6 +123,8 @@ const { subtle } = globalThis.crypto; assert.deepStrictEqual(secret1, secret2); } - test('X25519').then(common.mustCall()); - test('X448').then(common.mustCall()); + if (!process.features.openssl_is_boringssl) { + test('X25519').then(common.mustCall()); + test('X448').then(common.mustCall()); + } } diff --git a/test/parallel/test-webcrypto-derivekey.js b/test/parallel/test-webcrypto-derivekey.js index 558d37d90d5796..90f76839474e16 100644 --- a/test/parallel/test-webcrypto-derivekey.js +++ b/test/parallel/test-webcrypto-derivekey.js @@ -206,6 +206,8 @@ const { KeyObject } = require('crypto'); assert.deepStrictEqual(raw1, raw2); } - test('X25519').then(common.mustCall()); - test('X448').then(common.mustCall()); + if (!process.features.openssl_is_boringssl) { + test('X25519').then(common.mustCall()); + test('X448').then(common.mustCall()); + } } diff --git a/test/parallel/test-webcrypto-sign-verify.js b/test/parallel/test-webcrypto-sign-verify.js index de736102bdcb71..1b2b40152f88d2 100644 --- a/test/parallel/test-webcrypto-sign-verify.js +++ b/test/parallel/test-webcrypto-sign-verify.js @@ -121,8 +121,9 @@ const { subtle } = globalThis.crypto; name: 'Ed25519', }, publicKey, signature, ec.encode(data))); } - - test('hello world').then(common.mustCall()); + if (!process.features.openssl_is_boringssl) { + test('hello world').then(common.mustCall()); + } } // Test Sign/Verify Ed448 @@ -142,5 +143,7 @@ const { subtle } = globalThis.crypto; }, publicKey, signature, ec.encode(data))); } - test('hello world').then(common.mustCall()); + if (!process.features.openssl_is_boringssl) { + test('hello world').then(common.mustCall()); + } } diff --git a/test/parallel/test-webstorage.js b/test/parallel/test-webstorage.js index 7f9fe8dfa53391..9f9070df430f10 100644 --- a/test/parallel/test-webstorage.js +++ b/test/parallel/test-webstorage.js @@ -1,11 +1,11 @@ 'use strict'; -const common = require('../common'); +const { skipIfSQLiteMissing, spawnPromisified } = require('../common'); +skipIfSQLiteMissing(); const tmpdir = require('../common/tmpdir'); const assert = require('node:assert'); const { join } = require('node:path'); const { readdir } = require('node:fs/promises'); const { test, describe } = require('node:test'); -const { spawnPromisified } = common; let cnt = 0; tmpdir.refresh(); diff --git a/test/parallel/test-worker-internal-modules.mjs b/test/parallel/test-worker-internal-modules.mjs new file mode 100644 index 00000000000000..607eade85c5d45 --- /dev/null +++ b/test/parallel/test-worker-internal-modules.mjs @@ -0,0 +1,36 @@ +import '../common/index.mjs'; +import tmpdir from '../common/tmpdir.js'; +import assert from 'node:assert/strict'; +import { once } from 'node:events'; +import fs from 'node:fs/promises'; +import { describe, test, before } from 'node:test'; +import { Worker } from 'node:worker_threads'; + +const accessInternalsSource = ` +import 'node:internal/freelist'; +`; + +function convertScriptSourceToDataUrl(script) { + return new URL(`data:text/javascript,${encodeURIComponent(script)}`); +} + +describe('Worker threads should not be able to access internal modules', () => { + before(() => tmpdir.refresh()); + + test('worker instantiated with module file path', async () => { + const moduleFilepath = tmpdir.resolve('test-worker-internal-modules.mjs'); + await fs.writeFile(moduleFilepath, accessInternalsSource); + const w = new Worker(moduleFilepath); + await assert.rejects(once(w, 'exit'), { code: 'ERR_UNKNOWN_BUILTIN_MODULE' }); + }); + + test('worker instantiated with module source', async () => { + const w = new Worker(accessInternalsSource, { eval: true }); + await assert.rejects(once(w, 'exit'), { code: 'ERR_UNKNOWN_BUILTIN_MODULE' }); + }); + + test('worker instantiated with data: URL', async () => { + const w = new Worker(convertScriptSourceToDataUrl(accessInternalsSource)); + await assert.rejects(once(w, 'exit'), { code: 'ERR_UNKNOWN_BUILTIN_MODULE' }); + }); +}); diff --git a/test/parallel/test-zlib-type-error.js b/test/parallel/test-zlib-type-error.js new file mode 100644 index 00000000000000..3432d75e346ef1 --- /dev/null +++ b/test/parallel/test-zlib-type-error.js @@ -0,0 +1,46 @@ +'use strict'; +require('../common'); +const assert = require('assert').strict; +const test = require('node:test'); +const { DecompressionStream } = require('stream/web'); + +async function expectTypeError(promise) { + let threw = false; + try { + await promise; + } catch (err) { + threw = true; + assert(err instanceof TypeError, `Expected TypeError, got ${err}`); + } + assert(threw, 'Expected promise to reject'); +} + +test('DecompressStream deflat emits error on trailing data', async () => { + const valid = new Uint8Array([120, 156, 75, 4, 0, 0, 98, 0, 98]); // deflate('a') + const empty = new Uint8Array(1); + const invalid = new Uint8Array([...valid, ...empty]); + const double = new Uint8Array([...valid, ...valid]); + + for (const chunk of [[invalid], [valid, empty], [valid, valid], [valid, double]]) { + await expectTypeError( + Array.fromAsync( + new Blob([chunk]).stream().pipeThrough(new DecompressionStream('deflate')) + ) + ); + } +}); + +test('DecompressStream gzip emits error on trailing data', async () => { + const valid = new Uint8Array([31, 139, 8, 0, 0, 0, 0, 0, 0, 19, 75, 4, + 0, 67, 190, 183, 232, 1, 0, 0, 0]); // gzip('a') + const empty = new Uint8Array(1); + const invalid = new Uint8Array([...valid, ...empty]); + const double = new Uint8Array([...valid, ...valid]); + for (const chunk of [[invalid], [valid, empty], [valid, valid], [double]]) { + await expectTypeError( + Array.fromAsync( + new Blob([chunk]).stream().pipeThrough(new DecompressionStream('gzip')) + ) + ); + } +}); diff --git a/test/pseudo-tty/test-assert-colors.js b/test/pseudo-tty/test-assert-colors.js index 889e9a6e006e99..846326a9c4936a 100644 --- a/test/pseudo-tty/test-assert-colors.js +++ b/test/pseudo-tty/test-assert-colors.js @@ -1,4 +1,3 @@ -// Flags: --no-warnings 'use strict'; require('../common'); const assert = require('assert').strict; diff --git a/test/pseudo-tty/test-assert-no-color.js b/test/pseudo-tty/test-assert-no-color.js index c2e79d26701413..d6765d6f06c598 100644 --- a/test/pseudo-tty/test-assert-no-color.js +++ b/test/pseudo-tty/test-assert-no-color.js @@ -1,4 +1,3 @@ -// Flags: --no-warnings 'use strict'; require('../common'); const assert = require('assert').strict; diff --git a/test/pseudo-tty/test-tty-color-support.js b/test/pseudo-tty/test-tty-color-support.js index f846842ee015d8..6b122d85789951 100644 --- a/test/pseudo-tty/test-tty-color-support.js +++ b/test/pseudo-tty/test-tty-color-support.js @@ -37,13 +37,18 @@ const writeStream = new WriteStream(fd); [{ COLORTERM: '1' }, 4], [{ COLORTERM: 'truecolor' }, 24], [{ COLORTERM: '24bit' }, 24], - [{ TMUX: '1' }, 8], + [{ TMUX: '1' }, 24], [{ CI: '1' }, 1], - [{ CI: '1', TRAVIS: '1' }, 8], - [{ CI: '1', CIRCLECI: '1' }, 8], - [{ CI: '1', APPVEYOR: '1' }, 8], - [{ CI: '1', GITLAB_CI: '1' }, 8], + [{ CI: '', APPVEYOR: '1' }, 8], + [{ CI: '1', BUILDKITE: '' }, 8], [{ CI: '1', CI_NAME: 'codeship' }, 8], + [{ CI: '1', CIRCLECI: '1' }, 24], + [{ CI: '1', DRONE: '' }, 8], + [{ CI: '1', GITEA_ACTIONS: '' }, 24], + [{ CI: '1', GITHUB_ACTIONS: '' }, 24], + [{ CI: '1', GITLAB_CI: '1' }, 8], + [{ CI: '1', TRAVIS: '1' }, 8], + [{ CI: '', TRAVIS: '' }, 8], [{ TEAMCITY_VERSION: '1.0.0' }, 1], [{ TEAMCITY_VERSION: '9.11.0' }, 4], [{ TERM_PROGRAM: 'iTerm.app' }, 8], @@ -53,17 +58,22 @@ const writeStream = new WriteStream(fd); [{ TERM_PROGRAM: 'Hyper' }, 1], [{ TERM_PROGRAM: 'MacTerm' }, 24], [{ TERM_PROGRAM: 'Apple_Terminal' }, 8], - [{ TERM: 'xterm-256' }, 8], [{ TERM: 'ansi' }, 4], [{ TERM: 'ANSI' }, 4], [{ TERM: 'color' }, 4], - [{ TERM: 'linux' }, 4], - [{ TERM: 'fail' }, 1], [{ TERM: 'color', NODE_DISABLE_COLORS: '1' }, 1], + [{ TERM: 'console' }, 4], + [{ TERM: 'direct' }, 4], [{ TERM: 'dumb' }, 1], [{ TERM: 'dumb', COLORTERM: '1' }, 1], + [{ TERM: 'fail' }, 1], + [{ TERM: 'linux' }, 4], [{ TERM: 'terminator' }, 24], - [{ TERM: 'console' }, 4], + [{ TERM: 'vt100' }, 4], + [{ TERM: 'vt220' }, 4], + [{ TERM: 'xterm-256' }, 8], + [{ TERM: 'xterm-kitty' }, 24], + [{ TERM: 'xterm-truecolor' }, 24], [{ COLORTERM: '24bit', FORCE_COLOR: '' }, 4], [{ NO_COLOR: '1', FORCE_COLOR: '2' }, 8], [{ NODE_DISABLE_COLORS: '1', FORCE_COLOR: '3' }, 24], @@ -72,6 +82,7 @@ const writeStream = new WriteStream(fd); [{ TMUX: '1', FORCE_COLOR: 0 }, 1], [{ NO_COLOR: 'true', FORCE_COLOR: 0, COLORTERM: 'truecolor' }, 1], [{ TERM: 'xterm-256color', COLORTERM: 'truecolor' }, 24], + [{ TF_BUILD: '', AGENT_NAME: '' }, 4], ].forEach(([env, depth], i) => { const actual = writeStream.getColorDepth(env); assert.strictEqual( diff --git a/test/pummel/test-blob-slice-with-large-size.js b/test/pummel/test-blob-slice-with-large-size.js index 639c2217db79e3..af38d6d5760740 100644 --- a/test/pummel/test-blob-slice-with-large-size.js +++ b/test/pummel/test-blob-slice-with-large-size.js @@ -1,4 +1,7 @@ 'use strict'; + +// This tests that Blob.prototype.slice() works correctly when the size of the +// Blob is outside the range of 32-bit signed integers. const common = require('../common'); // Buffer with size > INT32_MAX @@ -14,8 +17,11 @@ try { const slicedBlob = blob.slice(size - 1, size); assert.strictEqual(slicedBlob.size, 1); } catch (e) { - if (e.code !== 'ERR_MEMORY_ALLOCATION_FAILED') { - throw e; + if (e.code === 'ERR_MEMORY_ALLOCATION_FAILED') { + common.skip('insufficient space for Buffer.allocUnsafe'); + } + if (/Array buffer allocation failed/.test(e.message)) { + common.skip('insufficient space for Blob.prototype.slice()'); } - common.skip('insufficient space for Buffer.allocUnsafe'); + throw e; } diff --git a/test/pummel/test-heapdump-http2.js b/test/pummel/test-heapdump-http2.js index c9218723792a1f..a3eccaecef4606 100644 --- a/test/pummel/test-heapdump-http2.js +++ b/test/pummel/test-heapdump-http2.js @@ -56,14 +56,11 @@ server.listen(0, () => { ], }, ], { loose: true }); - // `Node / StreamPipe` (C++) -> StreamPipe (JS) - state.validateSnapshotNodes('Node / StreamPipe', [ - { - children: [ - { node_name: 'StreamPipe', edge_name: 'native_to_javascript' }, - ], - }, - ]); + + // We don't necessarily have Node / StreamPipe here because by the time the + // response event is emitted, the file may have already been fully piped here + // and the stream pipe may have been destroyed. + // `Node / Http2Session` (C++) -> Http2Session (JS) state.validateSnapshotNodes('Node / Http2Session', [ { diff --git a/test/report/report.status b/test/report/report.status index 7ef99b5c8ed145..3832cb760db735 100644 --- a/test/report/report.status +++ b/test/report/report.status @@ -9,3 +9,7 @@ prefix report [$system==solaris] # Also applies to SmartOS # https://github.com/nodejs/node/issues/43457 test-report-fatal-error: PASS, FLAKY + +[$system==ibmi] +# https://github.com/nodejs/node/issues/58582 +test-report-exclude-network: PASS,FLAKY diff --git a/test/sequential/test-watch-mode-watch-flags.mjs b/test/sequential/test-watch-mode-watch-flags.mjs new file mode 100644 index 00000000000000..8cd08ee08a4c0e --- /dev/null +++ b/test/sequential/test-watch-mode-watch-flags.mjs @@ -0,0 +1,97 @@ +import * as common from '../common/index.mjs'; +import tmpdir from '../common/tmpdir.js'; +import assert from 'node:assert'; +import path from 'node:path'; +import { execPath } from 'node:process'; +import { describe, it } from 'node:test'; +import { spawn } from 'node:child_process'; +import { writeFileSync, mkdirSync } from 'node:fs'; +import { inspect } from 'node:util'; +import { createInterface } from 'node:readline'; + +if (common.isIBMi) + common.skip('IBMi does not support `fs.watch()`'); + +let tmpFiles = 0; +function createTmpFile(content, ext, basename) { + const file = path.join(basename, `${tmpFiles++}${ext}`); + writeFileSync(file, content); + return file; +} + +async function runNode({ + args, + expectedCompletionLog = 'Completed running', + options = {}, +}) { + const child = spawn(execPath, args, { encoding: 'utf8', stdio: 'pipe', ...options }); + let stderr = ''; + const stdout = []; + + child.stderr.on('data', (data) => { + stderr += data; + }); + + try { + // Break the chunks into lines + for await (const data of createInterface({ input: child.stdout })) { + if (!data.startsWith('Waiting for graceful termination') && !data.startsWith('Gracefully restarted')) { + stdout.push(data); + } + if (data.startsWith(expectedCompletionLog)) { + break; + } + } + } finally { + child.kill(); + } + return { stdout, stderr, pid: child.pid }; +} + +tmpdir.refresh(); + +describe('watch mode - watch flags', { concurrency: !process.env.TEST_PARALLEL, timeout: 60_000 }, () => { + it('when multiple `--watch` flags are provided should run as if only one was', async () => { + const projectDir = tmpdir.resolve('project-multi-flag'); + mkdirSync(projectDir); + + const file = createTmpFile(` + console.log( + process.argv.some(arg => arg === '--watch') + ? 'Error: unexpected --watch args present' + : 'no --watch args present' + );`, '.js', projectDir); + const args = ['--watch', '--watch', file]; + const { stdout, stderr } = await runNode({ + file, args, options: { cwd: projectDir } + }); + + assert.strictEqual(stderr, ''); + assert.deepStrictEqual(stdout, [ + 'no --watch args present', + `Completed running ${inspect(file)}. Waiting for file changes before restarting...`, + ]); + }); + + it('`--watch-path` args without `=` used alongside `--watch` should not make it into the script', async () => { + const projectDir = tmpdir.resolve('project-watch-watch-path-args'); + mkdirSync(projectDir); + + const file = createTmpFile(` + console.log( + process.argv.slice(2).some(arg => arg.endsWith('.js')) + ? 'some cli args end with .js' + : 'no cli arg ends with .js' + );`, '.js', projectDir); + const args = ['--watch', `--watch-path`, file, file]; + const { stdout, stderr } = await runNode({ + file, args, options: { cwd: projectDir } + }); + + assert.strictEqual(stderr, ''); + assert.deepStrictEqual(stdout, [ + 'no cli arg ends with .js', + `Completed running ${inspect(file)}. Waiting for file changes before restarting...`, + ]); + }); +}); diff --git a/test/wasm-allocation/wasm-allocation.status b/test/wasm-allocation/wasm-allocation.status index cf67fe9d67f20f..4663809cbd327a 100644 --- a/test/wasm-allocation/wasm-allocation.status +++ b/test/wasm-allocation/wasm-allocation.status @@ -6,5 +6,5 @@ prefix wasm-allocation [true] # This section applies to all platforms -[$system!=linux || $asan==on] +[$system!=linux || $asan==on || $pointer_compression==on] test-wasm-allocation: SKIP diff --git a/test/wpt/status/compression.json b/test/wpt/status/compression.json index 0cae222832e823..be073427810f0d 100644 --- a/test/wpt/status/compression.json +++ b/test/wpt/status/compression.json @@ -11,14 +11,6 @@ "compression-with-detach.tentative.window.js": { "requires": ["crypto"] }, - "decompression-corrupt-input.tentative.any.js": { - "fail": { - "expected": [ - "trailing junk for 'deflate' should give an error", - "trailing junk for 'gzip' should give an error" - ] - } - }, "idlharness-shadowrealm.window.js": { "skip": "ShadowRealm support is not enabled" }, diff --git a/test/wpt/status/resource-timing.json b/test/wpt/status/resource-timing.json index f40f8fe51da117..6406b88d3266f5 100644 --- a/test/wpt/status/resource-timing.json +++ b/test/wpt/status/resource-timing.json @@ -24,6 +24,8 @@ "fail": { "expected": [ "PerformanceResourceTiming interface: attribute firstInterimResponseStart", + "PerformanceResourceTiming interface: attribute finalResponseHeadersStart", + "PerformanceResourceTiming interface: resource must inherit property \"finalResponseHeadersStart\" with the proper type", "PerformanceResourceTiming interface: attribute renderBlockingStatus", "PerformanceResourceTiming interface: attribute contentType", "PerformanceResourceTiming interface: resource must inherit property \"firstInterimResponseStart\" with the proper type", diff --git a/test/wpt/test-webstorage.js b/test/wpt/test-webstorage.js index 6dc2a0369d53ad..490fac8ed7e232 100644 --- a/test/wpt/test-webstorage.js +++ b/test/wpt/test-webstorage.js @@ -1,4 +1,6 @@ 'use strict'; +const { skipIfSQLiteMissing } = require('../common'); +skipIfSQLiteMissing(); const tmpdir = require('../common/tmpdir'); const { WPTRunner } = require('../common/wpt'); const { join } = require('node:path'); diff --git a/tools/doc/type-parser.mjs b/tools/doc/type-parser.mjs index 928c430157f583..f9b0899ae22c72 100644 --- a/tools/doc/type-parser.mjs +++ b/tools/doc/type-parser.mjs @@ -87,23 +87,29 @@ const customTypesMap = { 'Verify': 'crypto.html#class-verify', 'crypto.constants': 'crypto.html#cryptoconstants', + 'Algorithm': 'webcrypto.html#class-algorithm', 'CryptoKey': 'webcrypto.html#class-cryptokey', 'CryptoKeyPair': 'webcrypto.html#class-cryptokeypair', 'Crypto': 'webcrypto.html#class-crypto', 'SubtleCrypto': 'webcrypto.html#class-subtlecrypto', 'RsaOaepParams': 'webcrypto.html#class-rsaoaepparams', - 'AlgorithmIdentifier': 'webcrypto.html#class-algorithmidentifier', 'AesCtrParams': 'webcrypto.html#class-aesctrparams', 'AesCbcParams': 'webcrypto.html#class-aescbcparams', 'AesDerivedKeyParams': 'webcrypto.html#class-aesderivedkeyparams', 'AesGcmParams': 'webcrypto.html#class-aesgcmparams', 'EcdhKeyDeriveParams': 'webcrypto.html#class-ecdhkeyderiveparams', 'HkdfParams': 'webcrypto.html#class-hkdfparams', + 'KeyAlgorithm': 'webcrypto.html#class-keyalgorithm', 'Pbkdf2Params': 'webcrypto.html#class-pbkdf2params', + 'HmacKeyAlgorithm': 'webcrypto.html#class-hmackeyalgorithm', 'HmacKeyGenParams': 'webcrypto.html#class-hmackeygenparams', + 'AesKeyAlgorithm': 'webcrypto.html#class-aeskeyalgorithm', 'AesKeyGenParams': 'webcrypto.html#class-aeskeygenparams', + 'RsaHashedKeyAlgorithm': + 'webcrypto.html#class-rsahashedkeyalgorithm', 'RsaHashedKeyGenParams': 'webcrypto.html#class-rsahashedkeygenparams', + 'EcKeyAlgorithm': 'webcrypto.html#class-eckeyalgorithm', 'EcKeyGenParams': 'webcrypto.html#class-eckeygenparams', 'RsaHashedImportParams': 'webcrypto.html#class-rsahashedimportparams', diff --git a/tools/eslint/package-lock.json b/tools/eslint/package-lock.json index 1f7900556493cf..77904109e425fd 100644 --- a/tools/eslint/package-lock.json +++ b/tools/eslint/package-lock.json @@ -8,14 +8,14 @@ "name": "eslint-tools", "version": "0.0.0", "dependencies": { - "@babel/core": "^7.26.10", - "@babel/eslint-parser": "^7.27.0", - "@babel/plugin-syntax-import-attributes": "^7.26.0", - "@babel/plugin-syntax-import-source": "^7.25.9", + "@babel/core": "^7.27.1", + "@babel/eslint-parser": "^7.27.1", + "@babel/plugin-syntax-import-attributes": "^7.27.1", + "@babel/plugin-syntax-import-source": "^7.27.1", "@stylistic/eslint-plugin-js": "^4.2.0", - "eslint": "^9.21.0", + "eslint": "^9.25.1", "eslint-formatter-tap": "^8.40.0", - "eslint-plugin-jsdoc": "^50.6.9", + "eslint-plugin-jsdoc": "^50.6.11", "eslint-plugin-markdown": "^5.1.0", "globals": "^16.0.0" } @@ -34,43 +34,44 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.26.2", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz", - "integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", + "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", + "license": "MIT", "dependencies": { - "@babel/helper-validator-identifier": "^7.25.9", + "@babel/helper-validator-identifier": "^7.27.1", "js-tokens": "^4.0.0", - "picocolors": "^1.0.0" + "picocolors": "^1.1.1" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/compat-data": { - "version": "7.26.5", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.26.5.tgz", - "integrity": "sha512-XvcZi1KWf88RVbF9wn8MN6tYFloU5qX8KjuF3E1PVBmJ9eypXfs4GRiJwLuTZL0iSnJUKn1BFPa5BPZZJyFzPg==", + "version": "7.27.3", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.27.3.tgz", + "integrity": "sha512-V42wFfx1ymFte+ecf6iXghnnP8kWTO+ZLXIyZq+1LAXHHvTZdVxicn4yiVYdYMGaCO3tmqub11AorKkv+iodqw==", "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.26.10", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.26.10.tgz", - "integrity": "sha512-vMqyb7XCDMPvJFFOaT9kxtiRh42GwlZEg1/uIgtZshS5a/8OaduUfCi7kynKgc3Tw/6Uo2D+db9qBttghhmxwQ==", + "version": "7.27.4", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.27.4.tgz", + "integrity": "sha512-bXYxrXFubeYdvB0NhD/NBB3Qi6aZeV20GOWVI47t2dkecCEoneR4NPVcb7abpXDEvejgrUfFtG6vG/zxAKmg+g==", "license": "MIT", "dependencies": { "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.26.2", - "@babel/generator": "^7.26.10", - "@babel/helper-compilation-targets": "^7.26.5", - "@babel/helper-module-transforms": "^7.26.0", - "@babel/helpers": "^7.26.10", - "@babel/parser": "^7.26.10", - "@babel/template": "^7.26.9", - "@babel/traverse": "^7.26.10", - "@babel/types": "^7.26.10", + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.27.3", + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-module-transforms": "^7.27.3", + "@babel/helpers": "^7.27.4", + "@babel/parser": "^7.27.4", + "@babel/template": "^7.27.2", + "@babel/traverse": "^7.27.4", + "@babel/types": "^7.27.3", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -86,9 +87,9 @@ } }, "node_modules/@babel/eslint-parser": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.27.0.tgz", - "integrity": "sha512-dtnzmSjXfgL/HDgMcmsLSzyGbEosi4DrGWoCNfuI+W4IkVJw6izpTe7LtOdwAXnkDqw5yweboYCTkM2rQizCng==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.27.1.tgz", + "integrity": "sha512-q8rjOuadH0V6Zo4XLMkJ3RMQ9MSBqwaDByyYB0izsYdaIWGNLmEblbCOf1vyFHICcg16CD7Fsi51vcQnYxmt6Q==", "license": "MIT", "dependencies": { "@nicolo-ribaudo/eslint-scope-5-internals": "5.1.1-v1", @@ -104,13 +105,13 @@ } }, "node_modules/@babel/generator": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.27.0.tgz", - "integrity": "sha512-VybsKvpiN1gU1sdMZIp7FcqphVVKEwcuj02x73uvcHE0PTihx1nlBcowYWhDwjpoAXRv43+gDzyggGnn1XZhVw==", + "version": "7.27.3", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.27.3.tgz", + "integrity": "sha512-xnlJYj5zepml8NXtjkG0WquFUv8RskFqyFcVgTBp5k+NaA/8uw/K+OSVf8AMGw5e9HKP2ETd5xpK5MLZQD6b4Q==", "license": "MIT", "dependencies": { - "@babel/parser": "^7.27.0", - "@babel/types": "^7.27.0", + "@babel/parser": "^7.27.3", + "@babel/types": "^7.27.3", "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25", "jsesc": "^3.0.2" @@ -120,13 +121,13 @@ } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.26.5", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.26.5.tgz", - "integrity": "sha512-IXuyn5EkouFJscIDuFF5EsiSolseme1s0CZB+QxVugqJLYmKdxI1VfIBOst0SUu4rnk2Z7kqTwmoO1lp3HIfnA==", + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", + "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.26.5", - "@babel/helper-validator-option": "^7.25.9", + "@babel/compat-data": "^7.27.2", + "@babel/helper-validator-option": "^7.27.1", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" @@ -136,25 +137,27 @@ } }, "node_modules/@babel/helper-module-imports": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz", - "integrity": "sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", + "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", + "license": "MIT", "dependencies": { - "@babel/traverse": "^7.25.9", - "@babel/types": "^7.25.9" + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.26.0.tgz", - "integrity": "sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==", + "version": "7.27.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.27.3.tgz", + "integrity": "sha512-dSOvYwvyLsWBeIRyOeHXp5vPj5l1I011r52FM1+r1jCERv+aFXYk4whgQccYEGYxK2H3ZAIA8nuPkQ0HaUo3qg==", + "license": "MIT", "dependencies": { - "@babel/helper-module-imports": "^7.25.9", - "@babel/helper-validator-identifier": "^7.25.9", - "@babel/traverse": "^7.25.9" + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1", + "@babel/traverse": "^7.27.3" }, "engines": { "node": ">=6.9.0" @@ -164,58 +167,61 @@ } }, "node_modules/@babel/helper-plugin-utils": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.25.9.tgz", - "integrity": "sha512-kSMlyUVdWe25rEsRGviIgOWnoT/nfABVWlqt9N19/dIPWViAOW2s9wznP5tURbs/IDuNk4gPy3YdYRgH3uxhBw==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz", + "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==", + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-string-parser": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz", - "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz", - "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", + "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-option": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.25.9.tgz", - "integrity": "sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helpers": { - "version": "7.26.10", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.26.10.tgz", - "integrity": "sha512-UPYc3SauzZ3JGgj87GgZ89JVdC5dj0AoetR5Bw6wj4niittNyFh6+eOGonYvJ1ao6B8lEa3Q3klS7ADZ53bc5g==", + "version": "7.27.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.27.4.tgz", + "integrity": "sha512-Y+bO6U+I7ZKaM5G5rDUZiYfUvQPUibYmAFe7EnKdnKBbVXDZxvp+MWOH5gYciY0EPk4EScsuFMQBbEfpdRKSCQ==", "license": "MIT", "dependencies": { - "@babel/template": "^7.26.9", - "@babel/types": "^7.26.10" + "@babel/template": "^7.27.2", + "@babel/types": "^7.27.3" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/parser": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.27.0.tgz", - "integrity": "sha512-iaepho73/2Pz7w2eMS0Q5f83+0RKI7i4xmiYeBmDzfRVbQtTOG7Ts0S4HzJVsTMGI9keU8rNfuZr8DKfSt7Yyg==", + "version": "7.27.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.27.4.tgz", + "integrity": "sha512-BRmLHGwpUqLFR2jzx9orBuX/ABDkj2jLKOXrHDTN2aOKL+jFDDKaRNo9nyYsIl9h/UE/7lMKdDjKQQyxKKDZ7g==", "license": "MIT", "dependencies": { - "@babel/types": "^7.27.0" + "@babel/types": "^7.27.3" }, "bin": { "parser": "bin/babel-parser.js" @@ -225,11 +231,12 @@ } }, "node_modules/@babel/plugin-syntax-import-attributes": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.26.0.tgz", - "integrity": "sha512-e2dttdsJ1ZTpi3B9UYGLw41hifAubg19AtCu/2I/F1QNVclOBr1dYpTdmdyZ84Xiz43BS/tCUkMAZNLv12Pi+A==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.27.1.tgz", + "integrity": "sha512-oFT0FrKHgF53f4vOsZGi2Hh3I35PfSmVs4IBFLFj4dnafP+hIWDLg3VyKmUHfLoLHlyxY4C7DGtmHuJgn+IGww==", + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -239,12 +246,12 @@ } }, "node_modules/@babel/plugin-syntax-import-source": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-source/-/plugin-syntax-import-source-7.25.9.tgz", - "integrity": "sha512-LlPeWMhPqu2YV1LADbJ0aSXxxfEIszdjB6k2Ih+p8c/slDAygf8Iy2FO9QO55APNTj5kamdf8CKXvg7OXngt8Q==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-source/-/plugin-syntax-import-source-7.27.1.tgz", + "integrity": "sha512-8MOQQZ+gIKsoB0RK9rpVsX+EXgiLHDAf4gH8ko4dIki5w1VeM6uBLv7dPZb5gGFVxoo0135wmpZ930HPqMrINw==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -254,30 +261,30 @@ } }, "node_modules/@babel/template": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.0.tgz", - "integrity": "sha512-2ncevenBqXI6qRMukPlXwHKHchC7RyMuu4xv5JBXRfOGVcTy1mXCD12qrp7Jsoxll1EV3+9sE4GugBVRjT2jFA==", + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", + "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.26.2", - "@babel/parser": "^7.27.0", - "@babel/types": "^7.27.0" + "@babel/code-frame": "^7.27.1", + "@babel/parser": "^7.27.2", + "@babel/types": "^7.27.1" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.27.0.tgz", - "integrity": "sha512-19lYZFzYVQkkHkl4Cy4WrAVcqBkgvV2YM2TU3xG6DIwO7O3ecbDPfW3yM3bjAGcqcQHi+CCtjMR3dIEHxsd6bA==", + "version": "7.27.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.27.4.tgz", + "integrity": "sha512-oNcu2QbHqts9BtOWJosOVJapWjBDSxGCpFvikNR5TGDYDQf3JwpIoMzIKrvfoti93cLfPJEG4tH9SPVeyCGgdA==", "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.26.2", - "@babel/generator": "^7.27.0", - "@babel/parser": "^7.27.0", - "@babel/template": "^7.27.0", - "@babel/types": "^7.27.0", + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.27.3", + "@babel/parser": "^7.27.4", + "@babel/template": "^7.27.2", + "@babel/types": "^7.27.3", "debug": "^4.3.1", "globals": "^11.1.0" }, @@ -289,47 +296,54 @@ "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "license": "MIT", "engines": { "node": ">=4" } }, "node_modules/@babel/types": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.27.0.tgz", - "integrity": "sha512-H45s8fVLYjbhFH62dIJ3WtmJ6RSPt/3DRO0ZcT2SUiYiQyz3BLVb9ADEnLl91m74aQPS3AzzeajZHYOalWe3bg==", + "version": "7.27.3", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.27.3.tgz", + "integrity": "sha512-Y1GkI4ktrtvmawoSq+4FCVHNryea6uR+qUQy0AGxLSsjCX0nVmkYQMBLHDkXZuo5hGx7eYdnIaslsdBFm7zbUw==", "license": "MIT", "dependencies": { - "@babel/helper-string-parser": "^7.25.9", - "@babel/helper-validator-identifier": "^7.25.9" + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@es-joy/jsdoccomment": { - "version": "0.49.0", - "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.49.0.tgz", - "integrity": "sha512-xjZTSFgECpb9Ohuk5yMX5RhUEbfeQcuOp8IF60e+wyzWEF0M5xeSgqsfLtvPEX8BIyOX9saZqzuGPmZ8oWc+5Q==", + "version": "0.50.2", + "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.50.2.tgz", + "integrity": "sha512-YAdE/IJSpwbOTiaURNCKECdAwqrJuFiZhylmesBcIRawtYKnBR2wxPhoIewMg+Yu+QuYvHfJNReWpoxGBKOChA==", + "license": "MIT", "dependencies": { + "@types/estree": "^1.0.6", + "@typescript-eslint/types": "^8.11.0", "comment-parser": "1.4.1", "esquery": "^1.6.0", "jsdoc-type-pratt-parser": "~4.1.0" }, "engines": { - "node": ">=16" + "node": ">=18" } }, "node_modules/@eslint-community/eslint-utils": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", - "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz", + "integrity": "sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==", "license": "MIT", "dependencies": { - "eslint-visitor-keys": "^3.3.0" + "eslint-visitor-keys": "^3.4.3" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, + "funding": { + "url": "https://opencollective.com/eslint" + }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } @@ -350,14 +364,15 @@ "version": "4.12.1", "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", + "license": "MIT", "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, "node_modules/@eslint/config-array": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.19.2.tgz", - "integrity": "sha512-GNKqxfHG2ySmJOBSHg7LxeUx4xpuCoFjacmlCoYWEbaPXLwvfIjixRI12xCQZeULksQb23uiA8F40w5TojpV7w==", + "version": "0.20.0", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.20.0.tgz", + "integrity": "sha512-fxlS1kkIjx8+vy2SjuCB94q3htSNrufYTXubwiBFeaQHbH6Ipi43gFJq2zCMt6PHhImH3Xmr0NksKDvchWlpQQ==", "license": "Apache-2.0", "dependencies": { "@eslint/object-schema": "^2.1.6", @@ -369,18 +384,18 @@ } }, "node_modules/@eslint/config-helpers": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.2.0.tgz", - "integrity": "sha512-yJLLmLexii32mGrhW29qvU3QBVTu0GUmEf/J4XsBtVhp4JkIUFN/BjWqTF63yRvGApIDpZm5fa97LtYtINmfeQ==", + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.2.2.tgz", + "integrity": "sha512-+GPzk8PlG0sPpzdU5ZvIRMPidzAnZDl/s9L+y13iodqvb8leL53bTannOrQ/Im7UkpsmFU5Ily5U60LWixnmLg==", "license": "Apache-2.0", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, "node_modules/@eslint/core": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.12.0.tgz", - "integrity": "sha512-cmrR6pytBuSMTaBweKoGMwu3EiHiEC+DoyupPmlZ0HxBJBtIxwe+j/E4XPIKNx+Q74c8lXKPwYawBf5glsTkHg==", + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.14.0.tgz", + "integrity": "sha512-qIbV0/JZr7iSDjqAc60IqbLdsj9GDt16xQtWD+B78d/HAlvysGdZZ6rpJHGAc2T0FQx1X6thsSPdnoiGKdNtdg==", "license": "Apache-2.0", "dependencies": { "@types/json-schema": "^7.0.15" @@ -425,12 +440,15 @@ } }, "node_modules/@eslint/js": { - "version": "9.23.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.23.0.tgz", - "integrity": "sha512-35MJ8vCPU0ZMxo7zfev2pypqTwWTofFZO6m4KAtdoFhRpLJUpHTZZ+KB3C7Hb1d7bULYwO4lJXGCi5Se+8OMbw==", + "version": "9.28.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.28.0.tgz", + "integrity": "sha512-fnqSjGWd/CoIp4EXIxWVK/sHA6DOHN4+8Ix2cX5ycOY7LG0UY8nHCU5pIp2eaE1Mc7Qd8kHspYNzYXT2ojPLzg==", "license": "MIT", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" } }, "node_modules/@eslint/object-schema": { @@ -443,12 +461,12 @@ } }, "node_modules/@eslint/plugin-kit": { - "version": "0.2.7", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.7.tgz", - "integrity": "sha512-JubJ5B2pJ4k4yGxaNLdbjrnk9d/iDz6/q8wOilpIowd6PJPgaxCuHBnBszq7Ce2TyMrywm5r4PnKm6V3iiZF+g==", + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.3.1.tgz", + "integrity": "sha512-0J+zgWxHN+xXONWIyPWKFMgVuJoZuGiIFu8yxk7RJjxkzpGmyja5wRFqZIVtjDVOQpV+Rw0iOAjYPE2eQyjr0w==", "license": "Apache-2.0", "dependencies": { - "@eslint/core": "^0.12.0", + "@eslint/core": "^0.14.0", "levn": "^0.4.1" }, "engines": { @@ -459,6 +477,7 @@ "version": "0.19.1", "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "license": "Apache-2.0", "engines": { "node": ">=18.18.0" } @@ -467,6 +486,7 @@ "version": "0.16.6", "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.6.tgz", "integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==", + "license": "Apache-2.0", "dependencies": { "@humanfs/core": "^0.19.1", "@humanwhocodes/retry": "^0.3.0" @@ -479,6 +499,7 @@ "version": "0.3.1", "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", + "license": "Apache-2.0", "engines": { "node": ">=18.18" }, @@ -501,9 +522,9 @@ } }, "node_modules/@humanwhocodes/retry": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.2.tgz", - "integrity": "sha512-xeO57FpIu4p1Ri3Jq/EXq4ClRm86dVF2z/+kvFnyqVYRavTZmaFaUBbWCOuuTh0o/g7DSsk6kc2vrS4Vl5oPOQ==", + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", "license": "Apache-2.0", "engines": { "node": ">=18.18" @@ -514,9 +535,9 @@ } }, "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", - "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz", + "integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==", "license": "MIT", "dependencies": { "@jridgewell/set-array": "^1.2.1", @@ -570,22 +591,10 @@ "eslint-scope": "5.1.1" } }, - "node_modules/@pkgr/core": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz", - "integrity": "sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==", - "license": "MIT", - "engines": { - "node": "^12.20.0 || ^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/unts" - } - }, "node_modules/@stylistic/eslint-plugin-js": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-js/-/eslint-plugin-js-4.2.0.tgz", - "integrity": "sha512-MiJr6wvyzMYl/wElmj8Jns8zH7Q1w8XoVtm+WM6yDaTrfxryMyb8n0CMxt82fo42RoLIfxAEtM6tmQVxqhk0/A==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-js/-/eslint-plugin-js-4.4.0.tgz", + "integrity": "sha512-UeeQNRF73zJXnNGGbvwgUgzS+vzVGQoRuQKR6RhQCRHQmaBaVHxDDQVmN9RPLCnRxVjO/v8cqq/yMDqC7DikSQ==", "license": "MIT", "dependencies": { "eslint-visitor-keys": "^4.2.0", @@ -602,6 +611,7 @@ "version": "4.2.0", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", + "license": "Apache-2.0", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, @@ -610,9 +620,10 @@ } }, "node_modules/@types/estree": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", - "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==" + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz", + "integrity": "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==", + "license": "MIT" }, "node_modules/@types/json-schema": { "version": "7.0.15", @@ -630,15 +641,29 @@ } }, "node_modules/@types/unist": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.10.tgz", - "integrity": "sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA==", + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz", + "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==", "license": "MIT" }, + "node_modules/@typescript-eslint/types": { + "version": "8.33.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.33.0.tgz", + "integrity": "sha512-DKuXOKpM5IDT1FA2g9x9x1Ug81YuKrzf4mYX8FAVSNu5Wo/LELHWQyM1pQaDkI42bX15PWl0vNPt1uGiIFUOpg==", + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, "node_modules/acorn": { - "version": "8.14.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", - "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", + "version": "8.14.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz", + "integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==", + "license": "MIT", "bin": { "acorn": "bin/acorn" }, @@ -718,9 +743,9 @@ } }, "node_modules/browserslist": { - "version": "4.24.4", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.4.tgz", - "integrity": "sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A==", + "version": "4.25.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.25.0.tgz", + "integrity": "sha512-PJ8gYKeS5e/whHBh8xrwYK+dAvEj7JXtz6uTucnMRB8OiGTsKccFekoRrjajPBHV8oOY+2tI4uxeceSimKwMFA==", "funding": [ { "type": "opencollective", @@ -737,10 +762,10 @@ ], "license": "MIT", "dependencies": { - "caniuse-lite": "^1.0.30001688", - "electron-to-chromium": "^1.5.73", + "caniuse-lite": "^1.0.30001718", + "electron-to-chromium": "^1.5.160", "node-releases": "^2.0.19", - "update-browserslist-db": "^1.1.1" + "update-browserslist-db": "^1.1.3" }, "bin": { "browserslist": "cli.js" @@ -759,9 +784,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001696", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001696.tgz", - "integrity": "sha512-pDCPkvzfa39ehJtJ+OwGT/2yvT2SbjfHhiIW2LWOAcMQ7BzwxT/XuyUp4OTOd0XFWA6BKw0JalnBHgSi5DGJBQ==", + "version": "1.0.30001720", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001720.tgz", + "integrity": "sha512-Ec/2yV2nNPwb4DnTANEV99ZWwm3ZWfdlfkQbWSDDt+PsXEVYwlhPH8tdMaPunYTKKmz7AnHi2oNEi1GcmKCD8g==", "funding": [ { "type": "opencollective", @@ -778,6 +803,22 @@ ], "license": "CC-BY-4.0" }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, "node_modules/character-entities": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-1.2.4.tgz", @@ -830,6 +871,7 @@ "version": "1.4.1", "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.4.1.tgz", "integrity": "sha512-buhp5kePrmda3vhc5B9t7pUQXAb2Tnd0qgpkIhPhkHXxJpiPJ11H0ZEU0oBpJ2QztSbzG/ZxMj/CHsYJqRHmyg==", + "license": "MIT", "engines": { "node": ">= 12.0.0" } @@ -850,6 +892,7 @@ "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "license": "MIT", "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -860,12 +903,12 @@ } }, "node_modules/debug": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", - "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", + "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", "license": "MIT", "dependencies": { - "ms": "2.1.2" + "ms": "^2.1.3" }, "engines": { "node": ">=6.0" @@ -883,17 +926,11 @@ "license": "MIT" }, "node_modules/electron-to-chromium": { - "version": "1.5.90", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.90.tgz", - "integrity": "sha512-C3PN4aydfW91Natdyd449Kw+BzhLmof6tzy5W1pFC5SpQxVXT+oyiyOG9AgYYSN9OdA/ik3YkCrpwqI8ug5Tug==", + "version": "1.5.161", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.161.tgz", + "integrity": "sha512-hwtetwfKNZo/UlwHIVBlKZVdy7o8bIZxxKs0Mv/ROPiQQQmDgdm5a+KvKtBsxM8ZjFzTaCeLoodZ8jiBE3o9rA==", "license": "ISC" }, - "node_modules/es-module-lexer": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.4.tgz", - "integrity": "sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw==", - "license": "MIT" - }, "node_modules/escalade": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", @@ -903,20 +940,32 @@ "node": ">=6" } }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/eslint": { - "version": "9.23.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.23.0.tgz", - "integrity": "sha512-jV7AbNoFPAY1EkFYpLq5bslU9NLNO8xnEeQXwErNibVryjk67wHVmddTBilc5srIttJDBrB0eMHKZBFbSIABCw==", + "version": "9.28.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.28.0.tgz", + "integrity": "sha512-ocgh41VhRlf9+fVpe7QKzwLj9c92fDiqOj8Y3Sd4/ZmVA4Btx4PlUYPq4pp9JDyupkf1upbEXecxL2mwNV7jPQ==", "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.12.1", - "@eslint/config-array": "^0.19.2", - "@eslint/config-helpers": "^0.2.0", - "@eslint/core": "^0.12.0", + "@eslint/config-array": "^0.20.0", + "@eslint/config-helpers": "^0.2.1", + "@eslint/core": "^0.14.0", "@eslint/eslintrc": "^3.3.1", - "@eslint/js": "9.23.0", - "@eslint/plugin-kit": "^0.2.7", + "@eslint/js": "9.28.0", + "@eslint/plugin-kit": "^0.3.1", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", @@ -976,22 +1025,21 @@ } }, "node_modules/eslint-plugin-jsdoc": { - "version": "50.6.9", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-50.6.9.tgz", - "integrity": "sha512-7/nHu3FWD4QRG8tCVqcv+BfFtctUtEDWc29oeDXB4bwmDM2/r1ndl14AG/2DUntdqH7qmpvdemJKwb3R97/QEw==", + "version": "50.7.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-50.7.1.tgz", + "integrity": "sha512-XBnVA5g2kUVokTNUiE1McEPse5n9/mNUmuJcx52psT6zBs2eVcXSmQBvjfa7NZdfLVSy3u1pEDDUxoxpwy89WA==", "license": "BSD-3-Clause", "dependencies": { - "@es-joy/jsdoccomment": "~0.49.0", + "@es-joy/jsdoccomment": "~0.50.2", "are-docs-informative": "^0.0.2", "comment-parser": "1.4.1", - "debug": "^4.3.6", + "debug": "^4.4.1", "escape-string-regexp": "^4.0.0", - "espree": "^10.1.0", + "espree": "^10.3.0", "esquery": "^1.6.0", - "parse-imports": "^2.1.1", - "semver": "^7.6.3", - "spdx-expression-parse": "^4.0.0", - "synckit": "^0.9.1" + "parse-imports-exports": "^0.2.4", + "semver": "^7.7.2", + "spdx-expression-parse": "^4.0.0" }, "engines": { "node": ">=18" @@ -1000,22 +1048,10 @@ "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0" } }, - "node_modules/eslint-plugin-jsdoc/node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/eslint-plugin-jsdoc/node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -1061,34 +1097,6 @@ "node": ">=10" } }, - "node_modules/eslint/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/eslint/node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/eslint/node_modules/eslint-scope": { "version": "8.3.0", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.3.0.tgz", @@ -1109,6 +1117,7 @@ "version": "4.2.0", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", + "license": "Apache-2.0", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, @@ -1129,6 +1138,7 @@ "version": "10.3.0", "resolved": "https://registry.npmjs.org/espree/-/espree-10.3.0.tgz", "integrity": "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==", + "license": "BSD-2-Clause", "dependencies": { "acorn": "^8.14.0", "acorn-jsx": "^5.3.2", @@ -1145,6 +1155,7 @@ "version": "4.2.0", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", + "license": "Apache-2.0", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, @@ -1272,9 +1283,9 @@ } }, "node_modules/flatted": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", - "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", "license": "ISC" }, "node_modules/gensync": { @@ -1299,9 +1310,9 @@ } }, "node_modules/globals": { - "version": "16.0.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-16.0.0.tgz", - "integrity": "sha512-iInW14XItCXET01CQFqudPOWP2jYMl7T+QRQT+UNcR/iQncN/F0UNpgd76iFkBPgNQb4+X3LV9tLJYzwh+Gl3A==", + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-16.2.0.tgz", + "integrity": "sha512-O+7l9tPdHCU320IigZZPj5zmRCFG9xHmx9cU8FqU2Rp+JN714seHV+2S9+JslCpY4gJwU2vOGox0wzgae/MCEg==", "license": "MIT", "engines": { "node": ">=18" @@ -1421,12 +1432,14 @@ "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "license": "ISC" }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "license": "MIT" }, "node_modules/js-yaml": { "version": "4.1.0", @@ -1444,14 +1457,16 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-4.1.0.tgz", "integrity": "sha512-Hicd6JK5Njt2QB6XYFS7ok9e37O8AYk3jTcppG4YVQnYjOemymvTcmc7OWsmq/Qqj5TdRFO5/x/tIPmBeRtGHg==", + "license": "MIT", "engines": { "node": ">=12.0.0" } }, "node_modules/jsesc": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz", - "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "license": "MIT", "bin": { "jsesc": "bin/jsesc" }, @@ -1601,9 +1616,9 @@ } }, "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "license": "MIT" }, "node_modules/natural-compare": { @@ -1695,19 +1710,21 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/parse-imports": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/parse-imports/-/parse-imports-2.1.1.tgz", - "integrity": "sha512-TDT4HqzUiTMO1wJRwg/t/hYk8Wdp3iF/ToMIlAoVQfL1Xs/sTxq1dKWSMjMbQmIarfWKymOyly40+zmPHXMqCA==", - "license": "Apache-2.0", + "node_modules/parse-imports-exports": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/parse-imports-exports/-/parse-imports-exports-0.2.4.tgz", + "integrity": "sha512-4s6vd6dx1AotCx/RCI2m7t7GCh5bDRUtGNvRfHSP2wbBQdMi67pPe7mtzmgwcaQ8VKK/6IB7Glfyu3qdZJPybQ==", + "license": "MIT", "dependencies": { - "es-module-lexer": "^1.5.3", - "slashes": "^3.0.12" - }, - "engines": { - "node": ">= 18" + "parse-statements": "1.0.11" } }, + "node_modules/parse-statements": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/parse-statements/-/parse-statements-1.0.11.tgz", + "integrity": "sha512-HlsyYdMBnbPQ9Jr/VgJ1YF4scnldvJpJxCVx6KgqPL4dxppsWrJHCIIxQXMJrqGnsRkNPATbeMJ8Yxu7JMsYcA==", + "license": "MIT" + }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -1721,6 +1738,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "license": "MIT", "engines": { "node": ">=8" } @@ -1728,7 +1746,8 @@ "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==" + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" }, "node_modules/prelude-ls": { "version": "1.2.1", @@ -1770,6 +1789,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "license": "MIT", "dependencies": { "shebang-regex": "^3.0.0" }, @@ -1781,16 +1801,11 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "license": "MIT", "engines": { "node": ">=8" } }, - "node_modules/slashes": { - "version": "3.0.12", - "resolved": "https://registry.npmjs.org/slashes/-/slashes-3.0.12.tgz", - "integrity": "sha512-Q9VME8WyGkc7pJf6QEkj3wE+2CnvZMI+XJhwdTPR8Z/kWQRXi7boAWLDibRPyHRTUTPx5FaU7MsyrjI3yLB4HA==", - "license": "ISC" - }, "node_modules/spdx-exceptions": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", @@ -1808,9 +1823,9 @@ } }, "node_modules/spdx-license-ids": { - "version": "3.0.18", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.18.tgz", - "integrity": "sha512-xxRs31BqRYHwiMzudOrpSiHtZ8i/GeionCBDSilhYRj+9gIcI8wCZTlXZKu9vZIVqViP3dcp9qE5G6AlIaD+TQ==", + "version": "3.0.21", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.21.tgz", + "integrity": "sha512-Bvg/8F5XephndSK3JffaRqdT+gyhfqIPwDHpX80tJrF8QQRYMo8sNMeaZ2Dp5+jhwKnUmIOyFFQfHRkjJm5nXg==", "license": "CC0-1.0" }, "node_modules/strip-json-comments": { @@ -1837,28 +1852,6 @@ "node": ">=8" } }, - "node_modules/synckit": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.9.1.tgz", - "integrity": "sha512-7gr8p9TQP6RAHusBOSLs46F4564ZrjV8xFmw5zCmgmhGUcw2hxsShhJ6CEiHQMgPDwAQ1fWHPM0ypc4RMAig4A==", - "license": "MIT", - "dependencies": { - "@pkgr/core": "^0.1.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/unts" - } - }, - "node_modules/tslib": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", - "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", - "license": "0BSD" - }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -1885,9 +1878,9 @@ } }, "node_modules/update-browserslist-db": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.2.tgz", - "integrity": "sha512-PPypAm5qvlD7XMZC3BujecnaOxwhrtoFR+Dqkk5Aa/6DssiH0ibKoketaj9w8LP7Bont1rYeoV5plxD7RTEPRg==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz", + "integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==", "funding": [ { "type": "opencollective", @@ -1927,6 +1920,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "license": "ISC", "dependencies": { "isexe": "^2.0.0" }, diff --git a/tools/eslint/package.json b/tools/eslint/package.json index da84af77f7822a..d0fbd7d433cc8a 100644 --- a/tools/eslint/package.json +++ b/tools/eslint/package.json @@ -3,14 +3,14 @@ "version": "0.0.0", "private": true, "dependencies": { - "@babel/core": "^7.26.10", - "@babel/eslint-parser": "^7.27.0", - "@babel/plugin-syntax-import-attributes": "^7.26.0", - "@babel/plugin-syntax-import-source": "^7.25.9", + "@babel/core": "^7.27.1", + "@babel/eslint-parser": "^7.27.1", + "@babel/plugin-syntax-import-attributes": "^7.27.1", + "@babel/plugin-syntax-import-source": "^7.27.1", "@stylistic/eslint-plugin-js": "^4.2.0", - "eslint": "^9.21.0", + "eslint": "^9.25.1", "eslint-formatter-tap": "^8.40.0", - "eslint-plugin-jsdoc": "^50.6.9", + "eslint-plugin-jsdoc": "^50.6.11", "eslint-plugin-markdown": "^5.1.0", "globals": "^16.0.0" } diff --git a/tools/install.py b/tools/install.py index 17515720ba9c85..8797b59e59c85a 100755 --- a/tools/install.py +++ b/tools/install.py @@ -181,9 +181,19 @@ def files(options, action): link_path = abspath(options.install_path, 'lib/libnode.so') try_symlink(options, so_name, link_path) else: - output_lib = 'libnode.' + options.variables.get('shlib_suffix') - action(options, [os.path.join(options.build_dir, output_lib)], - os.path.join(options.variables.get('libdir'), output_lib)) + # Ninja and Makefile generators output the library in different directories; + # find out which one we have, and install first found + output_lib_name = 'libnode.' + options.variables.get('shlib_suffix') + output_lib_candidate_paths = [ + os.path.join(options.build_dir, output_lib_name), + os.path.join(options.build_dir, "lib", output_lib_name), + ] + try: + output_lib = next(filter(os.path.exists, output_lib_candidate_paths)) + except StopIteration as not_found: + raise RuntimeError("No libnode.so to install!") from not_found + action(options, [output_lib], + os.path.join(options.variables.get('libdir'), output_lib_name)) action(options, [os.path.join(options.v8_dir, 'tools/gdbinit')], 'share/doc/node/') action(options, [os.path.join(options.v8_dir, 'tools/lldb_commands.py')], 'share/doc/node/') diff --git a/tools/sign.bat b/tools/sign.bat index f4d18d9f7a8a0d..607eb6de793ee3 100644 --- a/tools/sign.bat +++ b/tools/sign.bat @@ -1,12 +1,29 @@ @echo off -@REM From December 2023, new certificates use DigiCert cloud HSM service for EV signing. -@REM They provide a client side app smctl.exe for managing certificates and signing process. +@REM From June 2025, we started using Azure Trusted Signing for code signing. @REM Release CI machines are configured to have it in the PATH so this can be used safely. -smctl sign -k key_nodejs -i %1 + +where signtool >nul 2>&1 +if errorlevel 1 ( + echo signtool not found in PATH. + exit /b 1 +) + +if "%AZURE_SIGN_DLIB_PATH%"=="" ( + echo AZURE_SIGN_DLIB_PATH is not set. + exit /b 1 +) + +if "%AZURE_SIGN_METADATA_PATH%"=="" ( + echo AZURE_SIGN_METADATA_PATH is not set. + exit /b 1 +) + + +signtool sign /tr "http://timestamp.acs.microsoft.com" /td sha256 /fd sha256 /v /dlib %AZURE_SIGN_DLIB_PATH% /dmdf %AZURE_SIGN_METADATA_PATH% %1 if not ERRORLEVEL 1 ( - echo Successfully signed %1 using smctl + echo Successfully signed %1 using signtool exit /b 0 ) -echo Could not sign %1 using smctl +echo Could not sign %1 using signtool exit /b 1 \ No newline at end of file diff --git a/tools/test.py b/tools/test.py index ad3d0feb4edc17..83bb8c34db039e 100755 --- a/tools/test.py +++ b/tools/test.py @@ -31,7 +31,7 @@ from __future__ import print_function from typing import Dict import logging -import optparse +import argparse import os import re import signal @@ -1369,84 +1369,84 @@ def ReadConfigurationInto(path, sections, defs): def BuildOptions(): - result = optparse.OptionParser() - result.add_option("-m", "--mode", help="The test modes in which to run (comma-separated)", + result = argparse.ArgumentParser() + result.add_argument("-m", "--mode", help="The test modes in which to run (comma-separated)", default='release') - result.add_option("-v", "--verbose", help="Verbose output", + result.add_argument("-v", "--verbose", help="Verbose output", default=False, action="store_true") - result.add_option('--logfile', dest='logfile', + result.add_argument('--logfile', dest='logfile', help='write test output to file. NOTE: this only applies the tap progress indicator') - result.add_option("-p", "--progress", + result.add_argument("-p", "--progress", help="The style of progress indicator (%s)" % ", ".join(PROGRESS_INDICATORS.keys()), choices=list(PROGRESS_INDICATORS.keys()), default="mono") - result.add_option("--report", help="Print a summary of the tests to be run", + result.add_argument("--report", help="Print a summary of the tests to be run", default=False, action="store_true") - result.add_option("-s", "--suite", help="A test suite", + result.add_argument("-s", "--suite", help="A test suite", default=[], action="append") - result.add_option("-t", "--timeout", help="Timeout in seconds", - default=120, type="int") - result.add_option("--arch", help='The architecture to run tests for', + result.add_argument("-t", "--timeout", help="Timeout in seconds", + default=120, type=int) + result.add_argument("--arch", help='The architecture to run tests for', default='none') - result.add_option("--snapshot", help="Run the tests with snapshot turned on", + result.add_argument("--snapshot", help="Run the tests with snapshot turned on", default=False, action="store_true") - result.add_option("--special-command", default=None) - result.add_option("--node-args", dest="node_args", help="Args to pass through to Node", + result.add_argument("--special-command", default=None) + result.add_argument("--node-args", dest="node_args", help="Args to pass through to Node", default=[], action="append") - result.add_option("--expect-fail", dest="expect_fail", + result.add_argument("--expect-fail", dest="expect_fail", help="Expect test cases to fail", default=False, action="store_true") - result.add_option("--valgrind", help="Run tests through valgrind", + result.add_argument("--valgrind", help="Run tests through valgrind", default=False, action="store_true") - result.add_option("--worker", help="Run parallel tests inside a worker context", + result.add_argument("--worker", help="Run parallel tests inside a worker context", default=False, action="store_true") - result.add_option("--check-deopts", help="Check tests for permanent deoptimizations", + result.add_argument("--check-deopts", help="Check tests for permanent deoptimizations", default=False, action="store_true") - result.add_option("--cat", help="Print the source of the tests", + result.add_argument("--cat", help="Print the source of the tests", default=False, action="store_true") - result.add_option("--flaky-tests", + result.add_argument("--flaky-tests", help="Regard tests marked as flaky (run|skip|dontcare|keep_retrying)", default="run") - result.add_option("--measure-flakiness", + result.add_argument("--measure-flakiness", help="When a test fails, re-run it x number of times", - default=0, type="int") - result.add_option("--skip-tests", + default=0, type=int) + result.add_argument("--skip-tests", help="Tests that should not be executed (comma-separated)", default="") - result.add_option("--warn-unused", help="Report unused rules", + result.add_argument("--warn-unused", help="Report unused rules", default=False, action="store_true") - result.add_option("-j", help="The number of parallel tasks to run, 0=use number of cores", - default=0, type="int") - result.add_option("-J", help="For legacy compatibility, has no effect", + result.add_argument("-j", help="The number of parallel tasks to run, 0=use number of cores", + default=0, type=int) + result.add_argument("-J", help="For legacy compatibility, has no effect", default=False, action="store_true") - result.add_option("--time", help="Print timing information after running", + result.add_argument("--time", help="Print timing information after running", default=False, action="store_true") - result.add_option("--suppress-dialogs", help="Suppress Windows dialogs for crashing tests", + result.add_argument("--suppress-dialogs", help="Suppress Windows dialogs for crashing tests", dest="suppress_dialogs", default=True, action="store_true") - result.add_option("--no-suppress-dialogs", help="Display Windows dialogs for crashing tests", + result.add_argument("--no-suppress-dialogs", help="Display Windows dialogs for crashing tests", dest="suppress_dialogs", action="store_false") - result.add_option("--shell", help="Path to node executable", default=None) - result.add_option("--store-unexpected-output", + result.add_argument("--shell", help="Path to node executable", default=None) + result.add_argument("--store-unexpected-output", help="Store the temporary JS files from tests that fails", dest="store_unexpected_output", default=True, action="store_true") - result.add_option("--no-store-unexpected-output", + result.add_argument("--no-store-unexpected-output", help="Deletes the temporary JS files from tests that fails", dest="store_unexpected_output", action="store_false") - result.add_option("-r", "--run", + result.add_argument("-r", "--run", help="Divide the tests in m groups (interleaved) and run tests from group n (--run=n,m with n < m)", default="") - result.add_option('--temp-dir', + result.add_argument('--temp-dir', help='Optional path to change directory used for tests', default=False) - result.add_option('--test-root', + result.add_argument('--test-root', help='Optional path to change test directory', dest='test_root', default=None) - result.add_option('--repeat', + result.add_argument('--repeat', help='Number of times to repeat given tests', - default=1, type="int") - result.add_option('--abort-on-timeout', + default=1, type=int) + result.add_argument('--abort-on-timeout', help='Send SIGABRT instead of SIGTERM to kill processes that time out', default=False, action="store_true", dest="abort_on_timeout") - result.add_option("--type", + result.add_argument("--type", help="Type of build (simple, fips, coverage)", default=None) - result.add_option("--error-reporter", + result.add_argument("--error-reporter", help="use error reporter", default=True, action="store_true") return result @@ -1619,10 +1619,13 @@ def get_asan_state(vm, context): asan = Execute([vm, '-p', 'process.config.variables.asan'], context).stdout.strip() return "on" if asan == "1" else "off" +def get_pointer_compression_state(vm, context): + pointer_compression = Execute([vm, '-p', 'process.config.variables.v8_enable_pointer_compression'], context).stdout.strip() + return "on" if pointer_compression == "1" else "off" def Main(): parser = BuildOptions() - (options, args) = parser.parse_args() + (options, args) = parser.parse_known_args() if not ProcessOptions(options): parser.print_help() return 1 @@ -1717,6 +1720,7 @@ def Main(): 'arch': vmArch, 'type': get_env_type(vm, options.type, context), 'asan': get_asan_state(vm, context), + 'pointer_compression': get_pointer_compression_state(vm, context), } test_list = root.ListTests([], path, context, arch, mode) unclassified_tests += test_list diff --git a/tools/v8_gypfiles/d8.gyp b/tools/v8_gypfiles/d8.gyp index 0dc0859bd6868a..f5f8a194318eb5 100644 --- a/tools/v8_gypfiles/d8.gyp +++ b/tools/v8_gypfiles/d8.gyp @@ -41,7 +41,7 @@ }], ['(OS=="linux" or OS=="mac" or OS=="freebsd" or OS=="netbsd" \ or OS=="openbsd" or OS=="solaris" or OS=="android" \ - or OS=="qnx" or OS=="aix" or OS=="os400")', { + or OS=="qnx" or OS=="aix" or OS=="os400" or OS=="openharmony")', { 'sources': [ '<(V8_ROOT)/src/d8/d8-posix.cc', ] }], [ 'OS=="win"', { diff --git a/tools/v8_gypfiles/features.gypi b/tools/v8_gypfiles/features.gypi index 7940234cd6789c..1193bf6a896e01 100644 --- a/tools/v8_gypfiles/features.gypi +++ b/tools/v8_gypfiles/features.gypi @@ -73,7 +73,7 @@ }, { 'v8_enable_etw_stack_walking': 0, }], - ['OS=="linux"', { + ['OS=="linux" or OS=="openharmony"', { # Sets -dV8_ENABLE_PRIVATE_MAPPING_FORK_OPTIMIZATION. # # This flag speeds up the performance of fork/execve on Linux systems for @@ -252,6 +252,11 @@ # Sets -DV8_ENABLE_SANDBOX. 'v8_enable_sandbox%': 0, + # Enable support for external code range relative to the pointer compression + # cage. + # Sets -DV8_EXTERNAL_CODE_SPACE. + 'v8_enable_external_code_space%': 0, + # Experimental feature for collecting per-class zone memory stats. # Requires use_rtti = true 'v8_enable_precise_zone_stats%': 0, @@ -384,6 +389,9 @@ ['v8_enable_sandbox==1', { 'defines': ['V8_ENABLE_SANDBOX',], }], + ['v8_enable_external_code_space==1', { + 'defines': ['V8_EXTERNAL_CODE_SPACE',], + }], ['v8_enable_object_print==1', { 'defines': ['OBJECT_PRINT',], }], diff --git a/tools/v8_gypfiles/toolchain.gypi b/tools/v8_gypfiles/toolchain.gypi index 5bf396e074d755..d4fbee9820af88 100644 --- a/tools/v8_gypfiles/toolchain.gypi +++ b/tools/v8_gypfiles/toolchain.gypi @@ -86,10 +86,10 @@ 'binutils_dir%': '', 'conditions': [ - ['OS=="linux" and host_arch=="x64"', { + ['OS in "linux openharmony" and host_arch=="x64"', { 'binutils_dir%': 'third_party/binutils/Linux_x64/Release/bin', }], - ['OS=="linux" and host_arch=="ia32"', { + ['OS in "linux openharmony" and host_arch=="ia32"', { 'binutils_dir%': 'third_party/binutils/Linux_ia32/Release/bin', }], ], @@ -574,7 +574,7 @@ 'V8_TARGET_OS_IOS', ] }], - ['OS=="linux"', { + ['OS=="linux" or OS=="openharmony"', { 'defines': [ 'V8_HAVE_TARGET_OS', 'V8_TARGET_OS_LINUX', @@ -592,9 +592,7 @@ 'V8_TARGET_OS_WIN', ] }], - ['(OS=="linux" or OS=="freebsd" or OS=="openbsd" or OS=="solaris" \ - or OS=="netbsd" or OS=="mac" or OS=="android" or OS=="qnx") and \ - v8_target_arch=="ia32"', { + ['OS in "linux freebsd openbsd solaris netbsd mac android qnx openharmony" and v8_target_arch=="ia32"', { 'cflags': [ '-msse2', '-mfpmath=sse', @@ -703,7 +701,7 @@ 'DEBUG', ], 'conditions': [ - ['OS=="linux" and v8_enable_backtrace==1', { + ['OS in "linux openharmony" and v8_enable_backtrace==1', { # Support for backtrace_symbols. 'ldflags': [ '-rdynamic' ], }], @@ -750,8 +748,7 @@ 'v8_enable_slow_dchecks%': 1, }, 'conditions': [ - ['OS=="linux" or OS=="freebsd" or OS=="openbsd" or OS=="netbsd" or \ - OS=="qnx" or OS=="aix" or OS=="os400"', { + ['OS in "linux freebsd openbsd netbsd qnx aix os400 openharmony"', { 'cflags!': [ '-O3', '-O2', @@ -801,8 +798,7 @@ 'v8_enable_slow_dchecks%': 0, }, 'conditions': [ - ['OS=="linux" or OS=="freebsd" or OS=="openbsd" or OS=="netbsd" or \ - OS=="qnx" or OS=="aix" or OS=="os400"', { + ['OS in "linux freebsd openbsd netbsd qnx aix os400 openharmony"', { 'cflags!': [ '-O0', '-O1', @@ -850,8 +846,7 @@ # Temporary refs: https://github.com/nodejs/node/pull/23801 'defines!': ['ENABLE_HANDLE_ZAPPING',], 'conditions': [ - ['OS=="linux" or OS=="freebsd" or OS=="openbsd" or OS=="netbsd" \ - or OS=="aix" or OS=="os400"', { + ['OS in "linux freebsd openbsd netbsd aix os400 openharmony"', { 'cflags!': [ '-Os', ], diff --git a/tools/v8_gypfiles/v8.gyp b/tools/v8_gypfiles/v8.gyp index ee72dce827f74d..66b2f73cda63a9 100644 --- a/tools/v8_gypfiles/v8.gyp +++ b/tools/v8_gypfiles/v8.gyp @@ -702,7 +702,7 @@ }], ['v8_enable_webassembly==1', { 'conditions': [ - ['OS=="linux" or OS=="mac" or OS=="ios" or OS=="freebsd"', { + ['OS in "linux mac ios freebsd openharmony"', { 'sources': [ '<(V8_ROOT)/src/trap-handler/handler-inside-posix.h', ], @@ -745,12 +745,12 @@ }], ['v8_enable_webassembly==1', { 'conditions': [ - ['((_toolset=="host" and host_arch=="arm64" or _toolset=="target" and target_arch=="arm64") and (OS=="linux" or OS=="mac")) or ((_toolset=="host" and host_arch=="x64" or _toolset=="target" and target_arch=="x64") and (OS=="linux" or OS=="mac"))', { + ['((_toolset=="host" and host_arch=="arm64" or _toolset=="target" and target_arch=="arm64") and (OS in "linux mac openharmony")) or ((_toolset=="host" and host_arch=="x64" or _toolset=="target" and target_arch=="x64") and (OS in "linux mac openharmony"))', { 'sources': [ '<(V8_ROOT)/src/trap-handler/handler-inside-posix.h', ], }], - ['(_toolset=="host" and host_arch=="x64" or _toolset=="target" and target_arch=="x64") and (OS=="linux" or OS=="mac" or OS=="win")', { + ['(_toolset=="host" and host_arch=="x64" or _toolset=="target" and target_arch=="x64") and (OS in "linux mac win openharmony")', { 'sources': [ '<(V8_ROOT)/src/trap-handler/trap-handler-simulator.h', ], @@ -1166,7 +1166,7 @@ }], ['v8_enable_webassembly==1', { 'conditions': [ - ['OS=="linux" or OS=="mac" or OS=="ios" or OS=="freebsd"', { + ['OS in "linux mac ios freebsd openharmony"', { 'sources': [ '<(V8_ROOT)/src/trap-handler/handler-inside-posix.cc', '<(V8_ROOT)/src/trap-handler/handler-outside-posix.cc', @@ -1194,7 +1194,7 @@ 'conditions': [ ['v8_enable_webassembly==1', { 'conditions': [ - ['((_toolset=="host" and host_arch=="arm64" or _toolset=="target" and target_arch=="arm64") and (OS=="linux" or OS=="mac" or OS=="ios")) or ((_toolset=="host" and host_arch=="x64" or _toolset=="target" and target_arch=="x64") and (OS=="linux" or OS=="mac"))', { + ['((_toolset=="host" and host_arch=="arm64" or _toolset=="target" and target_arch=="arm64") and (OS in "linux mac ios openharmony")) or ((_toolset=="host" and host_arch=="x64" or _toolset=="target" and target_arch=="x64") and (OS in "linux mac openharmony"))', { 'sources': [ '<(V8_ROOT)/src/trap-handler/handler-inside-posix.cc', '<(V8_ROOT)/src/trap-handler/handler-outside-posix.cc', @@ -1206,7 +1206,7 @@ '<(V8_ROOT)/src/trap-handler/handler-outside-win.cc', ], }], - ['(_toolset=="host" and host_arch=="x64" or _toolset=="target" and target_arch=="x64") and (OS=="linux" or OS=="mac" or OS=="win")', { + ['(_toolset=="host" and host_arch=="x64" or _toolset=="target" and target_arch=="x64") and (OS in "linux mac win openharmony")', { 'sources': [ '<(V8_ROOT)/src/trap-handler/handler-outside-simulator.cc', ], @@ -1449,7 +1449,7 @@ }], ], }], - ['OS=="linux"', { + ['OS=="linux" or OS=="openharmony"', { 'sources': [ '<(V8_ROOT)/src/base/debug/stack_trace_posix.cc', '<(V8_ROOT)/src/base/platform/platform-linux.cc', diff --git a/typings/globals.d.ts b/typings/globals.d.ts index b37ce9428fd8f2..3ae6835c6fdc78 100644 --- a/typings/globals.d.ts +++ b/typings/globals.d.ts @@ -4,6 +4,7 @@ import { ConfigBinding } from './internalBinding/config'; import { ConstantsBinding } from './internalBinding/constants'; import { DebugBinding } from './internalBinding/debug'; import { HttpParserBinding } from './internalBinding/http_parser'; +import { InspectorBinding } from './internalBinding/inspector'; import { FsBinding } from './internalBinding/fs'; import { FsDirBinding } from './internalBinding/fs_dir'; import { MessagingBinding } from './internalBinding/messaging'; @@ -29,6 +30,7 @@ interface InternalBindingMap { fs: FsBinding; fs_dir: FsDirBinding; http_parser: HttpParserBinding; + inspector: InspectorBinding; messaging: MessagingBinding; modules: ModulesBinding; options: OptionsBinding; diff --git a/typings/internalBinding/blob.d.ts b/typings/internalBinding/blob.d.ts index 5396c863bb5e59..9a22c789e189bc 100644 --- a/typings/internalBinding/blob.d.ts +++ b/typings/internalBinding/blob.d.ts @@ -2,18 +2,10 @@ declare namespace InternalBlobBinding { interface BlobHandle { slice(start: number, end: number): BlobHandle; } - - class FixedSizeBlobCopyJob { - constructor(handle: BlobHandle); - run(): ArrayBuffer | undefined; - ondone: (err: unknown, res?: ArrayBuffer) => void; - } } export interface BlobBinding { createBlob(sources: Array, length: number): InternalBlobBinding.BlobHandle; - FixedSizeBlobCopyJob: typeof InternalBlobBinding.FixedSizeBlobCopyJob; getDataObject(id: string): [handle: InternalBlobBinding.BlobHandle | undefined, length: number, type: string] | undefined; storeDataObject(id: string, handle: InternalBlobBinding.BlobHandle, size: number, type: string): void; - revokeDataObject(id: string): void; } diff --git a/typings/internalBinding/constants.d.ts b/typings/internalBinding/constants.d.ts index dc4657080ba54b..2c645d99f17679 100644 --- a/typings/internalBinding/constants.d.ts +++ b/typings/internalBinding/constants.d.ts @@ -191,8 +191,6 @@ export interface ConstantsBinding { COPYFILE_FICLONE: 2; UV_FS_COPYFILE_FICLONE_FORCE: 4; COPYFILE_FICLONE_FORCE: 4; - EXTENSIONLESS_FORMAT_JAVASCRIPT: 0; - EXTENSIONLESS_FORMAT_WASM: 1; }; crypto: { OPENSSL_VERSION_NUMBER: 269488319; @@ -389,4 +387,8 @@ export interface ConstantsBinding { TRACE_EVENT_PHASE_LEAVE_CONTEXT: 41; TRACE_EVENT_PHASE_LINK_IDS: 61; }; + internal: { + EXTENSIONLESS_FORMAT_JAVASCRIPT: 0; + EXTENSIONLESS_FORMAT_WASM: 1; + }; } diff --git a/typings/internalBinding/fs.d.ts b/typings/internalBinding/fs.d.ts index 889769de209a16..72a0063281e6e9 100644 --- a/typings/internalBinding/fs.d.ts +++ b/typings/internalBinding/fs.d.ts @@ -77,6 +77,8 @@ declare namespace InternalFSBinding { function copyFile(src: StringOrBuffer, dest: StringOrBuffer, mode: number, usePromises: typeof kUsePromises): Promise; function cpSyncCheckPaths(src: StringOrBuffer, dest: StringOrBuffer, dereference: boolean, recursive: boolean): void; + function cpSyncOverrideFile(src: StringOrBuffer, dest: StringOrBuffer, mode: number, preserveTimestamps: boolean): void; + function cpSyncCopyDir(src: StringOrBuffer, dest: StringOrBuffer, force: boolean, errorOnExist: boolean, verbatimSymlinks: boolean, dereference: boolean): void; function fchmod(fd: number, mode: number, req: FSReqCallback): void; function fchmod(fd: number, mode: number): void; @@ -233,7 +235,7 @@ declare namespace InternalFSBinding { function writeString(fd: number, value: string, pos: unknown, encoding: unknown, req: undefined, ctx: FSSyncContext): number; function writeString(fd: number, value: string, pos: unknown, encoding: unknown, usePromises: typeof kUsePromises): Promise; - function getFormatOfExtensionlessFile(url: string): ConstantsBinding['fs']; + function getFormatOfExtensionlessFile(url: string): ConstantsBinding['internal']; function writeFileUtf8(path: string, data: string, flag: number, mode: number): void; function writeFileUtf8(fd: number, data: string, flag: number, mode: number): void; @@ -258,6 +260,8 @@ export interface FsBinding { close: typeof InternalFSBinding.close; copyFile: typeof InternalFSBinding.copyFile; cpSyncCheckPaths: typeof InternalFSBinding.cpSyncCheckPaths; + cpSyncOverrideFile: typeof InternalFSBinding.cpSyncOverrideFile; + cpSyncCopyDir: typeof InternalFSBinding.cpSyncCopyDir; fchmod: typeof InternalFSBinding.fchmod; fchown: typeof InternalFSBinding.fchown; fdatasync: typeof InternalFSBinding.fdatasync; diff --git a/typings/internalBinding/inspector.d.ts b/typings/internalBinding/inspector.d.ts new file mode 100644 index 00000000000000..ab32838b2366ca --- /dev/null +++ b/typings/internalBinding/inspector.d.ts @@ -0,0 +1,36 @@ +interface InspectorConnectionInstance { + dispatch(message: string): void; + disconnect(): void; +} + +interface InspectorConnectionConstructor { + new(onMessageHandler: (message: string) => void): InspectorConnectionInstance; +} + +export interface InspectorBinding { + consoleCall( + inspectorMethod: (...args: any[]) => any, + nodeMethod: (...args: any[]) => any, + ...args: any[] + ): void; + setConsoleExtensionInstaller(installer: Function): void; + callAndPauseOnStart( + fn: (...args: any[]) => any, + thisArg: any, + ...args: any[] + ): any; + open(port: number, host: string): void; + url(): string | undefined; + waitForDebugger(): boolean; + asyncTaskScheduled(taskName: string, taskId: number, recurring: boolean): void; + asyncTaskCanceled(taskId: number): void; + asyncTaskStarted(taskId: number): void; + asyncTaskFinished(taskId: number): void; + registerAsyncHook(enable: () => void, disable: () => void): void; + isEnabled(): boolean; + emitProtocolEvent(eventName: string, params: object): void; + setupNetworkTracking(enable: () => void, disable: () => void): void; + console: Console; + Connection: InspectorConnectionConstructor; + MainThreadConnection: InspectorConnectionConstructor; +} diff --git a/typings/internalBinding/messaging.d.ts b/typings/internalBinding/messaging.d.ts index 93a1a050887503..efcc67f0557342 100644 --- a/typings/internalBinding/messaging.d.ts +++ b/typings/internalBinding/messaging.d.ts @@ -23,7 +23,6 @@ export interface MessagingBinding { MessagePort: typeof InternalMessagingBinding.MessagePort; JSTransferable: typeof InternalMessagingBinding.JSTransferable; stopMessagePort(port: typeof InternalMessagingBinding.MessagePort): void; - checkMessagePort(port: unknown): boolean; drainMessagePort(port: typeof InternalMessagingBinding.MessagePort): void; receiveMessageOnPort(port: typeof InternalMessagingBinding.MessagePort): any; moveMessagePortToContext(port: typeof InternalMessagingBinding.MessagePort, context: any): typeof InternalMessagingBinding.MessagePort; diff --git a/typings/primordials.d.ts b/typings/primordials.d.ts index 22e95279618dfd..75c99ad0ee67eb 100644 --- a/typings/primordials.d.ts +++ b/typings/primordials.d.ts @@ -476,10 +476,29 @@ declare namespace primordials { constructor: new (length: number) => T, items: readonly TypedArrayContentType[], ): T; + export const TypedArray: TypedArray; + export const TypedArrayPrototype: + | typeof Uint8Array.prototype + | typeof Int8Array.prototype + | typeof Uint16Array.prototype + | typeof Int16Array.prototype + | typeof Uint32Array.prototype + | typeof Int32Array.prototype + | typeof Float32Array.prototype + | typeof Float64Array.prototype + | typeof BigInt64Array.prototype + | typeof BigUint64Array.prototype + | typeof Uint8ClampedArray.prototype; export const TypedArrayPrototypeGetBuffer: UncurryGetter; export const TypedArrayPrototypeGetByteLength: UncurryGetter; export const TypedArrayPrototypeGetByteOffset: UncurryGetter; export const TypedArrayPrototypeGetLength: UncurryGetter; + export function TypedArrayPrototypeAt(self: T, ...args: Parameters): ReturnType; + export function TypedArrayPrototypeIncludes(self: T, ...args: Parameters): ReturnType; + export function TypedArrayPrototypeFill(self: T, ...args: Parameters): ReturnType; + export function TypedArrayPrototypeSet(self: T, ...args: Parameters): ReturnType; + export function TypedArrayPrototypeSubarray(self: T, ...args: Parameters): ReturnType; + export function TypedArrayPrototypeSlice(self: T, ...args: Parameters): ReturnType; export function TypedArrayPrototypeGetSymbolToStringTag(self: unknown): | 'Int8Array' | 'Int16Array'