From 206aa1b88b9ea373dea86346983809327e1985b7 Mon Sep 17 00:00:00 2001 From: Carl Alexander Date: Thu, 22 Oct 2026 10:04:03 -0400 Subject: [PATCH 1/2] fix: backport October security fixes to legacy PHP runtimes Apply pinned CVE-2026-109618 and CVE-2026-109619 source backports for PHP 7.2 through 8.1, including the pristine-source prerequisites. Add bounded image regressions and non-publishing PR verification. Refs YMIR-127. No release or layer catalog changes. --- .dockerignore | 1 + .../workflows/build-publish-dev-images.yml | 46 +- .github/workflows/ci.yml | 21 +- runtime/patches/README.md | 205 +++ runtime/patches/SHA256SUMS | 11 + .../patches/php-7.2-7.3-multipart-limit.patch | 51 + runtime/patches/php-7.2-security.patch | 893 +++++++++++++ runtime/patches/php-7.2-zstr-max-len.patch | 23 + runtime/patches/php-7.3-security.patch | 912 +++++++++++++ runtime/patches/php-7.3-zstr-max-len.patch | 22 + runtime/patches/php-7.4-security.patch | 973 ++++++++++++++ runtime/patches/php-8.0-security.patch | 941 +++++++++++++ runtime/patches/php-8.1-security.patch | 1176 +++++++++++++++++ runtime/patches/provenance/sury-keyring.gpg | Bin 0 -> 3182 bytes .../patches/provenance/sury-trixie-InRelease | 93 ++ .../patches/provenance/sury-trixie-Sources.xz | Bin 0 -> 51348 bytes runtime/php-72/Dockerfile | 4 + runtime/php-73/Dockerfile | 4 + runtime/php-74/Dockerfile | 2 + runtime/php-80/Dockerfile | 2 + runtime/php-81/Dockerfile | 2 + runtime/security/request.php | 85 ++ runtime/security/verify.php | 200 +++ runtime/test-image.sh | 46 +- 24 files changed, 5690 insertions(+), 23 deletions(-) create mode 100644 runtime/patches/README.md create mode 100644 runtime/patches/SHA256SUMS create mode 100644 runtime/patches/php-7.2-7.3-multipart-limit.patch create mode 100644 runtime/patches/php-7.2-security.patch create mode 100644 runtime/patches/php-7.2-zstr-max-len.patch create mode 100644 runtime/patches/php-7.3-security.patch create mode 100644 runtime/patches/php-7.3-zstr-max-len.patch create mode 100644 runtime/patches/php-7.4-security.patch create mode 100644 runtime/patches/php-8.0-security.patch create mode 100644 runtime/patches/php-8.1-security.patch create mode 100644 runtime/patches/provenance/sury-keyring.gpg create mode 100644 runtime/patches/provenance/sury-trixie-InRelease create mode 100644 runtime/patches/provenance/sury-trixie-Sources.xz create mode 100644 runtime/security/request.php create mode 100644 runtime/security/verify.php diff --git a/.dockerignore b/.dockerignore index 733a9c4..5e5201b 100644 --- a/.dockerignore +++ b/.dockerignore @@ -4,5 +4,6 @@ !runtime/bootstrap !runtime/runtime.php !runtime/shared +!runtime/patches !src !templates diff --git a/.github/workflows/build-publish-dev-images.yml b/.github/workflows/build-publish-dev-images.yml index e805043..efaff3c 100644 --- a/.github/workflows/build-publish-dev-images.yml +++ b/.github/workflows/build-publish-dev-images.yml @@ -1,4 +1,4 @@ -name: Build and publish development images +name: Build and verify development images on: push: @@ -11,6 +11,14 @@ on: - 'src/**' - 'templates/**' - '.github/workflows/build-publish-dev-images.yml' + pull_request: + paths: + - 'composer.json' + - 'composer.lock' + - 'runtime/**' + - 'src/**' + - 'templates/**' + - '.github/workflows/build-publish-dev-images.yml' permissions: id-token: write @@ -21,7 +29,7 @@ env: jobs: publish: - name: Build and publish PHP ${{ matrix.php }} (${{ matrix.arch }}) + name: Build and verify PHP ${{ matrix.php }} (${{ matrix.arch }}) runs-on: ubuntu-latest strategy: fail-fast: false @@ -30,6 +38,12 @@ jobs: arch: [x86_64, arm64] steps: + - name: Require a trusted branch for image verification + if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name != github.repository + run: | + echo "::error::Image verification requires a trusted branch in this repository; fork pull requests are not verified." + exit 1 + - name: Set up QEMU to run ARM images uses: docker/setup-qemu-action@v4 @@ -40,6 +54,7 @@ jobs: uses: actions/checkout@v5 - name: Login to Docker Hub + if: github.event_name == 'push' && github.ref == 'refs/heads/main' uses: docker/login-action@v4 with: username: ${{ secrets.DOCKER_USERNAME }} @@ -48,17 +63,19 @@ jobs: - name: Determine Repository and Platform id: meta run: | - VERSION_CLEAN=$(echo ${{ matrix.php }} | sed 's/\.//g') - if [ "${{ matrix.arch }}" = "x86_64" ]; then - echo "repo=ymirapp/php-runtime-dev" >> $GITHUB_OUTPUT - echo "platform=linux/amd64" >> $GITHUB_OUTPUT - else - echo "repo=ymirapp/arm-php-runtime-dev" >> $GITHUB_OUTPUT - echo "platform=linux/arm64" >> $GITHUB_OUTPUT - fi - echo "tag=php-$VERSION_CLEAN" >> $GITHUB_OUTPUT - echo "compat_tag=php-${{ matrix.php }}" >> $GITHUB_OUTPUT - echo "dir=php-$VERSION_CLEAN" >> $GITHUB_OUTPUT + VERSION_CLEAN=$(echo '${{ matrix.php }}' | sed 's/\.//g') + { + if [ "${{ matrix.arch }}" = "x86_64" ]; then + echo "repo=ymirapp/php-runtime-dev" + echo "platform=linux/amd64" + else + echo "repo=ymirapp/arm-php-runtime-dev" + echo "platform=linux/arm64" + fi + echo "tag=php-$VERSION_CLEAN" + echo "compat_tag=php-${{ matrix.php }}" + echo "dir=php-$VERSION_CLEAN" + } >> "$GITHUB_OUTPUT" - name: Build and Load Image uses: depot/build-push-action@v1 @@ -68,6 +85,7 @@ jobs: file: runtime/${{ steps.meta.outputs.dir }}/Dockerfile platforms: ${{ steps.meta.outputs.platform }} load: true + push: false tags: | ${{ steps.meta.outputs.repo }}:${{ steps.meta.outputs.tag }} ${{ steps.meta.outputs.repo }}:${{ steps.meta.outputs.compat_tag }} @@ -79,6 +97,7 @@ jobs: run: ./runtime/test-image.sh ${{ steps.meta.outputs.repo }}:${{ steps.meta.outputs.tag }} ${{ steps.meta.outputs.platform }} - name: Build and Push Image + if: github.event_name == 'push' && github.ref == 'refs/heads/main' uses: depot/build-push-action@v1 with: project: ${{ secrets.DEPOT_PROJECT_ID }} @@ -94,6 +113,7 @@ jobs: DOCKER_PLATFORM=${{ steps.meta.outputs.platform }} - name: Verify Tag Aliases + if: github.event_name == 'push' && github.ref == 'refs/heads/main' run: | CANONICAL_IMAGE="${{ steps.meta.outputs.repo }}:${{ steps.meta.outputs.tag }}" COMPAT_IMAGE="${{ steps.meta.outputs.repo }}:${{ steps.meta.outputs.compat_tag }}" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 776b626..82fd7c0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -4,10 +4,23 @@ on: push: paths: - '.github/workflows/ci.yml' + - 'runtime/**' - 'src/**' - 'tests/**' - 'composer.json' - 'composer.lock' + pull_request: + paths: + - '.github/workflows/ci.yml' + - '.github/workflows/build-publish-dev-images.yml' + - 'runtime/**' + - 'src/**' + - 'tests/**' + - 'composer.json' + - 'composer.lock' + +permissions: + contents: read jobs: code-quality: @@ -23,11 +36,15 @@ jobs: - name: Install dependencies run: composer install --no-ansi --no-interaction --no-scripts --no-security-blocking --no-suggest --prefer-dist - name: Run PHP CS Fixer - run: composer php-cs-fixer + run: | + composer php-cs-fixer + composer php-cs-fixer -- --path-mode=override runtime/security - name: Run PHPStan run: composer phpstan - name: Run Rector - run: composer rector + run: | + composer rector + composer rector -- process runtime/security php-tests: name: Run tests on ${{ matrix.php-versions }} runs-on: ubuntu-latest diff --git a/runtime/patches/README.md b/runtime/patches/README.md new file mode 100644 index 0000000..a878007 --- /dev/null +++ b/runtime/patches/README.md @@ -0,0 +1,205 @@ +# Legacy PHP security backports (YMIR-127) + +Pinned minimal EOL mitigations for CVE-2026-109618 / GHSA-w8hw-w9fx-j79w +and CVE-2026-109619 / GHSA-6wmf-4rv5-p3rp. These do not restore upstream +support or include a distro's other historical security fixes. + +## Inputs and application order + +| Pristine source | Patches, in order | +| --- | --- | +| PHP 7.2.34 | `php-7.2-zstr-max-len.patch`, `php-7.2-security.patch`, `php-7.2-7.3-multipart-limit.patch` | +| PHP 7.3.33 | `php-7.3-zstr-max-len.patch`, `php-7.3-security.patch`, `php-7.2-7.3-multipart-limit.patch` | +| PHP 7.4.33 | `php-7.4-security.patch` (PHP security team) | +| PHP 8.0.30 | `php-8.0-security.patch` (PHP security team) | +| PHP 8.1.34 | `php-8.1-security.patch` (PHP security team) | + +The five security patches and two string-limit prerequisite patches are +byte-for-byte copies of the sources below. +`SHA256SUMS` pins all patch and retained provenance bytes: + +```sh +(cd runtime/patches && shasum -a 256 --check SHA256SUMS) +``` + +The Dockerfiles copy only the applicable patches into the build stage and +apply them after extraction, before `buildconf`. `git` is already installed; +`git apply` does not use fuzzy matching, does not partially accept a patch, +and returns failure for rejected hunks. All three 7.2/7.3 applications are +chained with `&&`, so failure of any patch stops the build. No new package or +network-fetched patch is required. Patches/provenance are not copied into +`/opt` or the exported layer. + +The repository build context must allow `runtime/patches/` through +`.dockerignore`; otherwise these `COPY` instructions deliberately fail. + +### Official PHP security-team patches + +Downloaded unchanged from these immutable commit patch URLs: + +- PHP 7.4: https://github.com/php/php-src/commit/712e60f9edfd03f0960fc4fc3c2c375f42b90aa2.patch +- PHP 8.0: https://github.com/php/php-src/commit/82f8f31b16a035c1b67cc253e79f7cc288f4cc20.patch +- PHP 8.1: https://github.com/php/php-src/commit/1d7dec178a094e6e75b229ce22754045f8c6070a.patch + +These are the exceptional EOL backports linked by PHP's October 21, 2026 +security announcement: https://www.php.net/archive/2026.php. +Commit/patch identity was checked over HTTPS, not by a Git commit signature. + +### Sury PHP 7.2/7.3 patches + +Use source patches, not Debian binaries or the entire distro patch series. + +- PHP 7.2 package `7.2.34-66+0~20261021.122+debian13~1.gbpe0bcd4`: + - Archive: https://packages.sury.org/php/pool/main/p/php7.2/php7.2_7.2.34-66%2B0~20261021.122%2Bdebian13~1.gbpe0bcd4.debian.tar.xz + - Archive SHA-256: `4a5a49d808a4d0cd4d32709fbf471519e8c04d81fbc8f237baae073a87454ee9` + - Security member: `debian/patches/0159-Avoid-state-corruption-via-bailout.patch` + - Prerequisite member: `debian/patches/0135-backport-ZSTR_MAX_LEN.patch` + - Adjacent `.dsc` SHA-256: `a06c4b5deeeed7ac81be430c95b74a9f456d21e19ca8d1aae8a2f319d4b1dcfe` +- PHP 7.3 package `7.3.33-35+0~20261021.144+debian13~1.gbpecf76f`: + - Archive: https://packages.sury.org/php/pool/main/p/php7.3/php7.3_7.3.33-35%2B0~20261021.144%2Bdebian13~1.gbpecf76f.debian.tar.xz + - Archive SHA-256: `0c65625f2cbd18749891f7a0bba653c7eabe5864155036cac9407508560eb983` + - Security member: `debian/patches/0139-Avoid-state-corruption-via-bailout.patch` + - Prerequisite member: `debian/patches/0107-backport-ZSTR_MAX_LEN.patch` + - Adjacent `.dsc` SHA-256: `c22d4541d5264ec53918b7d9b70b74121cdfeef1c6974b9fe4e9ad552b310575` + +All four patches are listed in their archive's `debian/patches/series`. + +#### Verified signature chain + +Verified October 22, 2026 using GnuPG, SHA-256, and archive member comparison: + +1. `provenance/sury-keyring.gpg` came from https://packages.sury.org/php/apt.gpg. + Primary key fingerprint: `15058500A0235D97F5D10063B188E2B695BD4743` + (`DEB.SURY.ORG Automatic Signing Key `). +2. `provenance/sury-trixie-InRelease` came from + https://packages.sury.org/php/dists/trixie/InRelease, dated + **2026-10-22 12:01:18 UTC**. `gpgv` returned a good signature and + `VALIDSIG` for that primary fingerprint. +3. Its SHA-256 entry authenticates `provenance/sury-trixie-Sources.xz`, from + https://packages.sury.org/php/dists/trixie/main/source/Sources.xz. +4. The `php7.2` and `php7.3` records authenticate the exact archive and `.dsc` + hashes above. Both archives also match their `.dsc` SHA-256 entries, and + their extracted security/prerequisite patch bytes match `SHA256SUMS`. + +The `.dsc` files are **unsigned**, not independently OpenPGP-signed. The +verified signature is on `InRelease`, covering them through the source +index. The trust anchor is Sury's HTTPS-distributed key, not an independently +established personal/web-of-trust identity. Retained index/signature bytes +are historical provenance, not a current APT freshness check. + +Replay the signature check (from the repository root): + +```sh +gpgv --keyring "$PWD/runtime/patches/provenance/sury-keyring.gpg" \ + runtime/patches/provenance/sury-trixie-InRelease +``` + +### Pristine PHP sources + +Archives are `https://www.php.net/distributions/php-.tar.gz`. +SHA-256 was rechecked against the corresponding `source` entry at +`https://www.php.net/releases/index.php?json&version=`: + +| Version | Archive SHA-256 | +| --- | --- | +| 7.2.34 | `8b2777c741e83f188d3ca6d8e98ece7264acafee86787298fae57e05d0dddc78` | +| 7.3.33 | `9a369c32c6f52036b0a890f290327f148a1904ee66aa56e2c9a7546da6525ec8` | +| 7.4.33 | `5a2337996f07c8a097e03d46263b5c98d2c8e355227756351421003bea8f463e` | +| 8.0.30 | `449d2048fcb20a314d8c218097c6d1047a9f1c5bb72aa54d5d3eba0a27a4c80c` | +| 8.1.34 | `3c5b060ec8e0d5dd1d8237823f3161cc8bc5342aab3c46893eba9857759c4bfa` | + +## The string-limit prerequisite + +The Sury security patches use `ZSTR_MAX_LEN`, also absent from pristine +7.2.34 and 7.3.33. A minimal AL2023 arm64 build of 7.2 initially failed in +`Zend/zend_vm_execute.h` with `ZSTR_MAX_LEN undeclared`; clean patch checks +did not expose this prerequisite. + +The two `php-7.x-zstr-max-len.patch` files add only `ZSTR_MAX_OVERHEAD` and +`ZSTR_MAX_LEN` (plus a blank line) to `Zend/zend_string.h`. The definitions +match pristine PHP 7.4.33 exactly and account for header/alignment overhead +before the new concatenation overflow checks. They are unchanged Sury +archive members from the same authenticated packages, not a wholesale +distro patch series. + +## The pristine-source multipart adaptation + +Sury's headers say `max_multipart_body_parts` was omitted because the distro +already had it. Neither pristine PHP 7.2.34 nor 7.3.33 has it. Applying only +the Sury patch therefore leaves a real hardening gap despite clean hunks. + +`php-7.2-7.3-multipart-limit.patch` restores **only the four omitted hunks** +from official PHP 7.4 commit `712e60f9edfd03f0960fc4fc3c2c375f42b90aa2`. +The hunk bytes, including context, are unchanged; only the patch envelope +is new. Both exact older sources accept them without fuzz after Sury's +patch. Apart from the two string-limit definitions above, no other distro +prerequisites or historical fixes are imported. + +- Register `max_multipart_body_parts`, default `-1`, system/per-directory. +- A negative setting derives the limit from `max_input_vars + max_file_uploads`. +- Count each part with Content-Disposition before parameter/body allocation. +- Warn and use the existing `fileupload_done` cleanup when exceeding the + limit; zero permits no such parts. Earlier accepted parts remain available. + +Review checked those registration, initialization, enforcement, and cleanup +sites against the official 7.4 implementation, not just patch applicability. + +## Verification and release gates + +All five checksum-verified source archives passed, in the order above: + +```sh +git apply --check /absolute/path/to/patch +patch --dry-run --batch --fuzz=0 -p1 -i /absolute/path/to/patch +git apply /absolute/path/to/patch +git apply --reverse --check /absolute/path/to/patch +``` + +Source assertions also checked the four adaptation hunks against official +7.4 bytes, proved the limit absent before/present after on 7.2/7.3, checked +its enforcement before parameter allocation, and checked allocator hard-exit +and session-progress disablement on all five versions, plus the required +string-limit definitions. Applicability and +source inspection alone are not proof of exploit prevention or a bootable +Lambda runtime. Each security patch was also tested with an intentionally +corrupted allocator hunk: `git apply` exited 1 without partially modifying +any source file. A scratch Docker build confirmed the pinned patches are +available through the repository build context. + +Minimal AL2023 **linux/arm64** builds of PHP 7.2.34 and 7.3.33 passed +`buildconf --force`, configuration, and `make -j2`, producing CLI, CGI, and +FPM binaries. Configuration was `CFLAGS=-O1 ./configure --disable-all +--enable-cli --enable-cgi --enable-fpm --enable-session --enable-json +--without-pear`. The repository's `runtime/security/verify.php` also passed +against both minimal builds: normal/nested uploads, upload-progress +disablement, explicit/derived multipart limits, warm-worker state reset, +FPM OOM/child replacement/warm recovery, and CLI OOM/failure exit codes. +These used the runtime's FastCGI/process wrappers, but are not full Ymir +image or extension builds. + +Before release, require both-architecture builds and +`runtime/test-image.sh ` for all five versions, including +upload/nested-form behavior, multipart boundaries, OOM child replacement and +next-request health, session upload-progress disablement, and CLI/queue +failure behavior. The minimal source checks do not validate extensions, +PHP-FPM lifecycle, complete images, layer exports, or earlier/future CVEs. + +### Customer impact and rollback + +- **OOM exits the process immediately with status 1**, bypassing normal PHP + shutdown functions/destructors. An invocation may fail after side effects; + do not add automatic application retries as part of this patch. +- **PHP session upload-progress tracking is disabled unconditionally**, even + if its INI setting is enabled. Ordinary uploads remain supported. +- Multipart limits and ignored duplicate/unused MIME headers can change + malformed or unusually large multipart requests. +- Existing Lambda deployments are not patched retroactively. After separately + authorized publishing/catalog synchronization, zip deployments need a new + deploy; container deployments need patched-base rebuilds and redeployment + (including digest updates where pinned). +- Preserve prior artifacts for recovery. Reverting these changes or deploying + an old image/layer restores the vulnerabilities; prefer a forward fix and + explicitly communicate renewed exposure if rollback is unavoidable. + +No publishing, tags, catalogs, layer names, image aliases, bootstrap paths, +or PHP versions are changed by these source backports. diff --git a/runtime/patches/SHA256SUMS b/runtime/patches/SHA256SUMS new file mode 100644 index 0000000..d441d91 --- /dev/null +++ b/runtime/patches/SHA256SUMS @@ -0,0 +1,11 @@ +3aa3c16bf76aa929c2140b8ef2632682194fecc4fbd549a08e4980238ea30e34 php-7.2-7.3-multipart-limit.patch +35f4820ab80594899db860be6f6d695657509d6186a830fefd5f442bc2bd0330 php-7.2-security.patch +b4da10ce4bb9aaf57dc3de71f21d200a5a331aec7c34b8c7b946b1db3b9c7e1f php-7.2-zstr-max-len.patch +38b59430a69a7d61919f8875c5d2fa6ff8d4dfaa9277fefc3098be41371af3f0 php-7.3-security.patch +0a9e65e27c04e17b7fb876b639ef769f707ff403d9f2e51330d22fb2047586a1 php-7.3-zstr-max-len.patch +5fe57ca6ee96d59b36c6e0ca842843c50884f177bef1e85234cf669b577f5e48 php-7.4-security.patch +534478c973cef6f493605b7af907f639a364912ee92c24598ddae44c3bc72d1c php-8.0-security.patch +c85ad0fddcbff7f2318617eeaa54d271135463b5bf70a01228447e3ed78de96e php-8.1-security.patch +b486fd5488185c4c46467960fa69c53d5085fec492cf76b9eaf3db33561c9d7c provenance/sury-keyring.gpg +3cdc3b580e315a6c214f9723af0c4663f7498c48c09eedfd325681ff801a3f63 provenance/sury-trixie-InRelease +bce36b31bf6b87c32bc8a8f28112502f78e26bf4f2c247b5a4a2d07e20d34c09 provenance/sury-trixie-Sources.xz diff --git a/runtime/patches/php-7.2-7.3-multipart-limit.patch b/runtime/patches/php-7.2-7.3-multipart-limit.patch new file mode 100644 index 0000000..34e89f6 --- /dev/null +++ b/runtime/patches/php-7.2-7.3-multipart-limit.patch @@ -0,0 +1,51 @@ +Subject: Restore the multipart limit omitted by the Sury 7.2/7.3 backports + +Apply after the matching Sury security patch to pristine upstream sources. +These four hunks are unchanged from PHP security-team commit +712e60f9edfd03f0960fc4fc3c2c375f42b90aa2; only the patch headers differ. +The distro already had this limit, but pristine PHP 7.2.34/7.3.33 did not. + +--- a/main/main.c ++++ b/main/main.c +@@ -836,6 +836,7 @@ PHP_INI_BEGIN() + PHP_INI_ENTRY("disable_functions", "", PHP_INI_SYSTEM, NULL) + PHP_INI_ENTRY("disable_classes", "", PHP_INI_SYSTEM, NULL) + PHP_INI_ENTRY("max_file_uploads", "20", PHP_INI_SYSTEM|PHP_INI_PERDIR, NULL) ++ PHP_INI_ENTRY("max_multipart_body_parts", "-1", PHP_INI_SYSTEM|PHP_INI_PERDIR, NULL) + + STD_PHP_INI_BOOLEAN("allow_url_fopen", "1", PHP_INI_SYSTEM, OnUpdateBool, allow_url_fopen, php_core_globals, core_globals) + STD_PHP_INI_BOOLEAN("allow_url_include", "0", PHP_INI_SYSTEM, OnUpdateBool, allow_url_include, php_core_globals, core_globals) +--- a/main/rfc1867.c ++++ b/main/rfc1867.c +@@ -694,6 +708,7 @@ SAPI_API SAPI_POST_HANDLER_FUNC(rfc1867_post_handler) /* {{{ */ + void *event_extra_data = NULL; + unsigned int llen = 0; + int upload_cnt = INI_INT("max_file_uploads"); ++ int body_parts_cnt = INI_INT("max_multipart_body_parts"); + const zend_encoding *internal_encoding = zend_multibyte_get_internal_encoding(); + php_rfc1867_getword_t getword; + php_rfc1867_getword_conf_t getword_conf; +@@ -715,6 +730,11 @@ SAPI_API SAPI_POST_HANDLER_FUNC(rfc1867_post_handler) /* {{{ */ + return; + } + ++ if (body_parts_cnt < 0) { ++ body_parts_cnt = PG(max_input_vars) + upload_cnt; ++ } ++ int body_parts_limit = body_parts_cnt; ++ + /* Get the boundary */ + boundary = strstr(content_type_dup, "boundary"); + if (!boundary) { +@@ -799,6 +819,11 @@ SAPI_API SAPI_POST_HANDLER_FUNC(rfc1867_post_handler) /* {{{ */ + char *pair = NULL; + int end = 0; + ++ if (--body_parts_cnt < 0) { ++ php_error_docref(NULL, E_WARNING, "Multipart body parts limit exceeded %d. To increase the limit change max_multipart_body_parts in php.ini.", body_parts_limit); ++ goto fileupload_done; ++ } ++ + while (isspace(*cd)) { + ++cd; + } diff --git a/runtime/patches/php-7.2-security.patch b/runtime/patches/php-7.2-security.patch new file mode 100644 index 0000000..7339fc5 --- /dev/null +++ b/runtime/patches/php-7.2-security.patch @@ -0,0 +1,893 @@ +From: Arnaud Le Blanc +Date: Sun, 18 Oct 2026 20:09:54 +0200 +Subject: Avoid state corruption via bailout + +Minimal mitigation for EOL version. + +Fix GHSA-w8hw-w9fx-j79w (CVE-2026-109618) +Fix GHSA-6wmf-4rv5-p3rp (CVE-2026-109619) + +Backported from the PHP 7.4 version: +- shutdown_executor() frees the object store before the error handlers, + so the fast shutdown resets are done just before + zend_objects_store_free_object_storage(). +- "|| 1" instead of "|| true" in the session upload progress callback + (no stdbool.h). +- The max_multipart_body_parts hunk of the 7.4 patch is left out, the + code is already there. +- array_init_singleton() is implemented in zend_API.c, there is no + zend_new_array(); HT_HASH_RESET() uses memset(), so the SSE2 change is + not needed. + +Co-authored-by: Ilija Tovilo +--- + Zend/zend_API.c | 8 +++ + Zend/zend_API.h | 2 + + Zend/zend_alloc.c | 68 +++++++++++++++++-------- + Zend/zend_alloc.h | 2 + + Zend/zend_execute_API.c | 15 ++++++ + Zend/zend_hash.c | 6 +-- + Zend/zend_llist.c | 2 + + Zend/zend_multiply.h | 4 +- + Zend/zend_strtod.c | 4 +- + Zend/zend_vm_def.h | 12 +++++ + Zend/zend_vm_execute.h | 108 ++++++++++++++++++++++++++++++++++++++++ + ext/session/session.c | 2 +- + main/SAPI.c | 5 ++ + main/main.c | 5 ++ + main/php_variables.c | 8 +-- + main/rfc1867.c | 29 ++++++++--- + 16 files changed, 240 insertions(+), 40 deletions(-) + +diff --git a/Zend/zend_API.c b/Zend/zend_API.c +index 604450e9..738266cf 100644 +--- a/Zend/zend_API.c ++++ b/Zend/zend_API.c +@@ -1093,6 +1093,14 @@ ZEND_API int _array_init(zval *arg, uint32_t size ZEND_FILE_LINE_DC) /* {{{ */ + } + /* }}} */ + ++ZEND_API int _array_init_singleton(zval *arg ZEND_FILE_LINE_DC) /* {{{ */ ++{ ++ _array_init(arg, 0 ZEND_FILE_LINE_RELAY_CC); ++ Z_ARRVAL_P(arg)->nTableSize = 1; ++ return SUCCESS; ++} ++/* }}} */ ++ + /* This function should be called after the constructor has been called + * because it may call __set from the uninitialized object otherwise. */ + ZEND_API void zend_merge_properties(zval *obj, HashTable *properties) /* {{{ */ +diff --git a/Zend/zend_API.h b/Zend/zend_API.h +index 38407703..763c64ab 100644 +--- a/Zend/zend_API.h ++++ b/Zend/zend_API.h +@@ -392,10 +392,12 @@ ZEND_API char *zend_get_type_by_const(int type); + + #define array_init(arg) _array_init((arg), 0 ZEND_FILE_LINE_CC) + #define array_init_size(arg, size) _array_init((arg), (size) ZEND_FILE_LINE_CC) ++#define array_init_singleton(arg) _array_init_singleton((arg) ZEND_FILE_LINE_CC) + #define object_init(arg) _object_init((arg) ZEND_FILE_LINE_CC) + #define object_init_ex(arg, ce) _object_init_ex((arg), (ce) ZEND_FILE_LINE_CC) + #define object_and_properties_init(arg, ce, properties) _object_and_properties_init((arg), (ce), (properties) ZEND_FILE_LINE_CC) + ZEND_API int _array_init(zval *arg, uint32_t size ZEND_FILE_LINE_DC); ++ZEND_API int _array_init_singleton(zval *arg ZEND_FILE_LINE_DC); + ZEND_API int _object_init(zval *arg ZEND_FILE_LINE_DC); + ZEND_API int _object_init_ex(zval *arg, zend_class_entry *ce ZEND_FILE_LINE_DC); + ZEND_API int _object_and_properties_init(zval *arg, zend_class_entry *ce, HashTable *properties ZEND_FILE_LINE_DC); +diff --git a/Zend/zend_alloc.c b/Zend/zend_alloc.c +index f4a61795..4b914251 100644 +--- a/Zend/zend_alloc.c ++++ b/Zend/zend_alloc.c +@@ -59,6 +59,7 @@ + #include "zend_operators.h" + #include "zend_multiply.h" + #include "zend_bitset.h" ++#include "zend_execute.h" + + #ifdef HAVE_SIGNAL_H + # include +@@ -360,7 +361,42 @@ static ZEND_COLD ZEND_NORETURN void zend_mm_panic(const char *message) + #if ZEND_DEBUG && defined(HAVE_KILL) && defined(HAVE_GETPID) + kill(getpid(), SIGSEGV); + #endif +- exit(1); ++ _exit(1); ++} ++ ++ZEND_API ZEND_COLD ZEND_NORETURN void zend_mm_safe_error_ex(const char *format, ...) ++{ ++ zend_string *script_filename = NULL; ++ uint32_t script_lineno = 0; ++ ++ if (zend_is_executing()) { ++ script_filename = zend_get_executed_filename_ex(); ++ script_lineno = zend_get_executed_lineno(); ++ } else if (zend_is_compiling()) { ++ script_filename = zend_get_compiled_filename(); ++ script_lineno = zend_get_compiled_lineno(); ++ } ++ ++ va_list args; ++ va_start(args, format); ++ ++ char buf[1024]; ++ vsnprintf(buf, sizeof(buf), format, args); ++ ++ va_end(args); ++ ++ fprintf(stderr, ++ "\nFatal error: %s in %s on line %d\n", ++ buf, ++ script_filename ? ZSTR_VAL(script_filename) : "Unknown", ++ script_lineno); ++ ++ /* See http://support.microsoft.com/kb/190351 */ ++# ifdef ZEND_WIN32 ++ fflush(stderr); ++# endif ++ ++ _exit(1); + } + + static ZEND_COLD ZEND_NORETURN void zend_mm_safe_error(zend_mm_heap *heap, +@@ -372,22 +408,14 @@ static ZEND_COLD ZEND_NORETURN void zend_mm_safe_error(zend_mm_heap *heap, + #endif + size_t size) + { ++ (void) heap; + +- heap->overflow = 1; +- zend_try { +- zend_error_noreturn(E_ERROR, +- format, +- limit, ++ zend_mm_safe_error_ex(format, limit, + #if ZEND_DEBUG +- filename, +- lineno, ++ filename, ++ lineno, + #endif +- size); +- } zend_catch { +- } zend_end_try(); +- heap->overflow = 0; +- zend_bailout(); +- exit(1); ++ size); + } + + #ifdef _WIN32 +@@ -1338,7 +1366,7 @@ static zend_always_inline void *zend_mm_alloc_heap(zend_mm_heap *heap, size_t si + size = MAX(size, 1); + size = ZEND_MM_ALIGNED_SIZE(size) + ZEND_MM_ALIGNED_SIZE(sizeof(zend_mm_debug_info)); + if (UNEXPECTED(size < real_size)) { +- zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%zu + %zu)", ZEND_MM_ALIGNED_SIZE(real_size), ZEND_MM_ALIGNED_SIZE(sizeof(zend_mm_debug_info))); ++ zend_mm_safe_error_ex("Possible integer overflow in memory allocation (%zu + %zu)", ZEND_MM_ALIGNED_SIZE(real_size), ZEND_MM_ALIGNED_SIZE(sizeof(zend_mm_debug_info))); + return NULL; + } + #endif +@@ -1731,7 +1759,7 @@ static void *zend_mm_alloc_huge(zend_mm_heap *heap, size_t size ZEND_FILE_LINE_D + void *ptr; + + if (UNEXPECTED(new_size < size)) { +- zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%zu + %zu)", size, alignment); ++ zend_mm_safe_error_ex("Possible integer overflow in memory allocation (%zu + %zu)", size, alignment); + } + + #if ZEND_MM_LIMIT +@@ -2527,7 +2555,7 @@ ZEND_API char* ZEND_FASTCALL _estrdup(const char *s ZEND_FILE_LINE_DC ZEND_FILE_ + + length = strlen(s); + if (UNEXPECTED(length + 1 == 0)) { +- zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (1 * %zu + 1)", length); ++ zend_mm_safe_error_ex("Possible integer overflow in memory allocation (1 * %zu + 1)", length); + } + p = (char *) _emalloc(length + 1 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC); + memcpy(p, s, length+1); +@@ -2539,7 +2567,7 @@ ZEND_API char* ZEND_FASTCALL _estrndup(const char *s, size_t length ZEND_FILE_LI + char *p; + + if (UNEXPECTED(length + 1 == 0)) { +- zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (1 * %zu + 1)", length); ++ zend_mm_safe_error_ex("Possible integer overflow in memory allocation (1 * %zu + 1)", length); + } + p = (char *) _emalloc(length + 1 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC); + memcpy(p, s, length); +@@ -2553,7 +2581,7 @@ ZEND_API char* ZEND_FASTCALL zend_strndup(const char *s, size_t length) + char *p; + + if (UNEXPECTED(length + 1 == 0)) { +- zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (1 * %zu + 1)", length); ++ zend_mm_safe_error_ex("Possible integer overflow in memory allocation (1 * %zu + 1)", length); + } + p = (char *) malloc(length + 1); + if (UNEXPECTED(p == NULL)) { +@@ -2827,7 +2855,7 @@ ZEND_API zend_mm_heap *zend_mm_startup_ex(const zend_mm_handlers *handlers, void + static ZEND_COLD ZEND_NORETURN void zend_out_of_memory(void) + { + fprintf(stderr, "Out of memory\n"); +- exit(1); ++ _exit(1); + } + + ZEND_API void * __zend_malloc(size_t len) +diff --git a/Zend/zend_alloc.h b/Zend/zend_alloc.h +index e3ab221e..334004c5 100644 +--- a/Zend/zend_alloc.h ++++ b/Zend/zend_alloc.h +@@ -399,6 +399,8 @@ static void apc_init_heap(void) + + */ + ++ZEND_API ZEND_COLD ZEND_NORETURN void zend_mm_safe_error_ex(const char *format, ...); ++ + END_EXTERN_C() + + #endif +diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c +index 9f10843b..99d4ffa6 100644 +--- a/Zend/zend_execute_API.c ++++ b/Zend/zend_execute_API.c +@@ -263,8 +263,21 @@ void shutdown_executor(void) /* {{{ */ + zend_close_rsrc_list(&EG(regular_list)); + } zend_end_try(); + ++ if (fast_shutdown) { ++ /* may be used by zend_error before init_executor */ ++ ZVAL_UNDEF(&EG(user_error_handler)); ++ ZVAL_UNDEF(&EG(user_exception_handler)); ++ memset(&EG(user_error_handlers_error_reporting), 0, sizeof(EG(user_error_handlers_error_reporting))); ++ memset(&EG(user_error_handlers), 0, sizeof(EG(user_error_handlers))); ++ memset(&EG(user_exception_handlers), 0, sizeof(EG(user_exception_handlers))); ++ } ++ + zend_objects_store_free_object_storage(&EG(objects_store), fast_shutdown); + ++ /* may be used by zend_error before init_executor */ ++ EG(error_handling) = EH_NORMAL; ++ EG(exception) = NULL; ++ + /* All resources and objects are destroyed. */ + /* No PHP callback functions may be called after this point. */ + EG(active) = 0; +@@ -299,6 +312,8 @@ void shutdown_executor(void) /* {{{ */ + } ZEND_HASH_FOREACH_END_DEL(); + + zend_cleanup_internal_classes(); ++ EG(objects_store).object_buckets = NULL; ++ EG(objects_store).top = 1; + } else { + zend_hash_graceful_reverse_destroy(&EG(symbol_table)); + +diff --git a/Zend/zend_hash.c b/Zend/zend_hash.c +index f5fba679..d6c022a2 100644 +--- a/Zend/zend_hash.c ++++ b/Zend/zend_hash.c +@@ -103,7 +103,7 @@ static zend_always_inline uint32_t zend_hash_check_size(uint32_t nSize) + if (nSize < HT_MIN_SIZE) { + nSize = HT_MIN_SIZE; + } else if (UNEXPECTED(nSize >= HT_MAX_SIZE)) { +- zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%u * %zu + %zu)", nSize, sizeof(Bucket), sizeof(Bucket)); ++ zend_mm_safe_error_ex("Possible integer overflow in memory allocation (%u * %zu + %zu)", nSize, sizeof(Bucket), sizeof(Bucket)); + } + + #if defined(ZEND_WIN32) +@@ -189,7 +189,7 @@ static void ZEND_FASTCALL zend_hash_packed_grow(HashTable *ht) + { + HT_ASSERT_RC1(ht); + if (ht->nTableSize >= HT_MAX_SIZE) { +- zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%u * %zu + %zu)", ht->nTableSize * 2, sizeof(Bucket), sizeof(Bucket)); ++ zend_mm_safe_error_ex("Possible integer overflow in memory allocation (%u * %zu + %zu)", ht->nTableSize * 2, sizeof(Bucket), sizeof(Bucket)); + } + ht->nTableSize += ht->nTableSize; + HT_SET_DATA_ADDR(ht, perealloc2(HT_GET_DATA_ADDR(ht), HT_SIZE(ht), HT_USED_SIZE(ht), ht->u.flags & HASH_FLAG_PERSISTENT)); +@@ -865,7 +865,7 @@ static void ZEND_FASTCALL zend_hash_do_resize(HashTable *ht) + pefree(old_data, ht->u.flags & HASH_FLAG_PERSISTENT); + zend_hash_rehash(ht); + } else { +- zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%u * %zu + %zu)", ht->nTableSize * 2, sizeof(Bucket) + sizeof(uint32_t), sizeof(Bucket)); ++ zend_mm_safe_error_ex("Possible integer overflow in memory allocation (%u * %zu + %zu)", ht->nTableSize * 2, sizeof(Bucket) + sizeof(uint32_t), sizeof(Bucket)); + } + } + +diff --git a/Zend/zend_llist.c b/Zend/zend_llist.c +index de93f295..4b0509cb 100644 +--- a/Zend/zend_llist.c ++++ b/Zend/zend_llist.c +@@ -114,6 +114,8 @@ ZEND_API void zend_llist_destroy(zend_llist *l) + current = next; + } + ++ l->head = NULL; ++ l->tail = NULL; + l->count = 0; + } + +diff --git a/Zend/zend_multiply.h b/Zend/zend_multiply.h +index 26853a3c..386f9353 100644 +--- a/Zend/zend_multiply.h ++++ b/Zend/zend_multiply.h +@@ -309,7 +309,7 @@ static zend_always_inline size_t zend_safe_address_guarded(size_t nmemb, size_t + size_t ret = zend_safe_address(nmemb, size, offset, &overflow); + + if (UNEXPECTED(overflow)) { +- zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%zu * %zu + %zu)", nmemb, size, offset); ++ zend_mm_safe_error_ex("Possible integer overflow in memory allocation (%zu * %zu + %zu)", nmemb, size, offset); + return 0; + } + return ret; +@@ -322,7 +322,7 @@ static zend_always_inline size_t zend_safe_addmult(size_t nmemb, size_t size, si + size_t ret = zend_safe_address(nmemb, size, offset, &overflow); + + if (UNEXPECTED(overflow)) { +- zend_error_noreturn(E_ERROR, "Possible integer overflow in %s (%zu * %zu + %zu)", message, nmemb, size, offset); ++ zend_mm_safe_error_ex("Possible integer overflow in %s (%zu * %zu + %zu)", message, nmemb, size, offset); + return 0; + } + return ret; +diff --git a/Zend/zend_strtod.c b/Zend/zend_strtod.c +index 3aa99f8d..01c1779d 100644 +--- a/Zend/zend_strtod.c ++++ b/Zend/zend_strtod.c +@@ -600,7 +600,7 @@ Balloc + rv = (Bigint *)MALLOC(sizeof(Bigint) + (x-1)*sizeof(ULong)); + if (!rv) { + FREE_DTOA_LOCK(0); +- zend_error_noreturn(E_ERROR, "Balloc() failed to allocate memory"); ++ zend_mm_safe_error_ex("Balloc() failed to allocate memory"); + } + #else + len = (sizeof(Bigint) + (x-1)*sizeof(ULong) + sizeof(double) - 1) +@@ -613,7 +613,7 @@ Balloc + rv = (Bigint*)MALLOC(len*sizeof(double)); + if (!rv) { + FREE_DTOA_LOCK(0); +- zend_error_noreturn(E_ERROR, "Balloc() failed to allocate memory"); ++ zend_mm_safe_error_ex("Balloc() failed to allocate memory"); + } + #endif + rv->k = k; +diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h +index ed84d17b..ebdb2fdc 100644 +--- a/Zend/zend_vm_def.h ++++ b/Zend/zend_vm_def.h +@@ -316,11 +316,17 @@ ZEND_VM_HANDLER(8, ZEND_CONCAT, CONST|TMPVAR|CV, CONST|TMPVAR|CV) + !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { + size_t len = ZSTR_LEN(op1_str); + ++ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + ZVAL_NEW_STR(EX_VAR(opline->result.var), str); + break; + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -2716,11 +2722,17 @@ ZEND_VM_HANDLER(53, ZEND_FAST_CONCAT, CONST|TMPVAR|CV, CONST|TMPVAR|CV) + !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { + size_t len = ZSTR_LEN(op1_str); + ++ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + ZVAL_NEW_STR(EX_VAR(opline->result.var), str); + break; + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h +index 3f975dec..b0170aff 100644 +--- a/Zend/zend_vm_execute.h ++++ b/Zend/zend_vm_execute.h +@@ -4406,11 +4406,17 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_CONST_CONST_HANDLE + !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { + size_t len = ZSTR_LEN(op1_str); + ++ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + ZVAL_NEW_STR(EX_VAR(opline->result.var), str); + break; + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -5202,11 +5208,17 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CONST_CONST_H + !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { + size_t len = ZSTR_LEN(op1_str); + ++ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + ZVAL_NEW_STR(EX_VAR(opline->result.var), str); + break; + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -8524,11 +8536,17 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_CONST_CV_HANDLER(Z + !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { + size_t len = ZSTR_LEN(op1_str); + ++ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + ZVAL_NEW_STR(EX_VAR(opline->result.var), str); + break; + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -9253,11 +9271,17 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CONST_CV_HAND + !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { + size_t len = ZSTR_LEN(op1_str); + ++ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + ZVAL_NEW_STR(EX_VAR(opline->result.var), str); + break; + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -10580,11 +10604,17 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_CONST_TMPVAR_HANDL + !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { + size_t len = ZSTR_LEN(op1_str); + ++ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + ZVAL_NEW_STR(EX_VAR(opline->result.var), str); + break; + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -11275,11 +11305,17 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CONST_TMPVAR_ + !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { + size_t len = ZSTR_LEN(op1_str); + ++ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + ZVAL_NEW_STR(EX_VAR(opline->result.var), str); + break; + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -35136,11 +35172,17 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_CV_CONST_HANDLER(Z + !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { + size_t len = ZSTR_LEN(op1_str); + ++ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + ZVAL_NEW_STR(EX_VAR(opline->result.var), str); + break; + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -37690,11 +37732,17 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CV_CONST_HAND + !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { + size_t len = ZSTR_LEN(op1_str); + ++ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + ZVAL_NEW_STR(EX_VAR(opline->result.var), str); + break; + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -41657,11 +41705,17 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_CV_CV_HANDLER(ZEND + !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { + size_t len = ZSTR_LEN(op1_str); + ++ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + ZVAL_NEW_STR(EX_VAR(opline->result.var), str); + break; + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -44200,11 +44254,17 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CV_CV_HANDLER + !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { + size_t len = ZSTR_LEN(op1_str); + ++ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + ZVAL_NEW_STR(EX_VAR(opline->result.var), str); + break; + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -45369,11 +45429,17 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_CV_TMPVAR_HANDLER( + !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { + size_t len = ZSTR_LEN(op1_str); + ++ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + ZVAL_NEW_STR(EX_VAR(opline->result.var), str); + break; + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -47770,11 +47836,17 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CV_TMPVAR_HAN + !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { + size_t len = ZSTR_LEN(op1_str); + ++ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + ZVAL_NEW_STR(EX_VAR(opline->result.var), str); + break; + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -49343,11 +49415,17 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_TMPVAR_CONST_HANDL + !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { + size_t len = ZSTR_LEN(op1_str); + ++ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + ZVAL_NEW_STR(EX_VAR(opline->result.var), str); + break; + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -49957,11 +50035,17 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_TMPVAR_CONST_ + !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { + size_t len = ZSTR_LEN(op1_str); + ++ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + ZVAL_NEW_STR(EX_VAR(opline->result.var), str); + break; + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -51749,11 +51833,17 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_TMPVAR_CV_HANDLER( + !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { + size_t len = ZSTR_LEN(op1_str); + ++ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + ZVAL_NEW_STR(EX_VAR(opline->result.var), str); + break; + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -52294,11 +52384,17 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_TMPVAR_CV_HAN + !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { + size_t len = ZSTR_LEN(op1_str); + ++ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + ZVAL_NEW_STR(EX_VAR(opline->result.var), str); + break; + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -53079,11 +53175,17 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_TMPVAR_TMPVAR_HAND + !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { + size_t len = ZSTR_LEN(op1_str); + ++ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + ZVAL_NEW_STR(EX_VAR(opline->result.var), str); + break; + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -53625,11 +53727,17 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_TMPVAR_TMPVAR + !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { + size_t len = ZSTR_LEN(op1_str); + ++ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + ZVAL_NEW_STR(EX_VAR(opline->result.var), str); + break; + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +diff --git a/ext/session/session.c b/ext/session/session.c +index 0f0d9bcb..8be81f6d 100644 +--- a/ext/session/session.c ++++ b/ext/session/session.c +@@ -3071,7 +3071,7 @@ static int php_session_rfc1867_callback(unsigned int event, void *event_data, vo + if (php_session_rfc1867_orig_callback) { + retval = php_session_rfc1867_orig_callback(event, event_data, extra); + } +- if (!PS(rfc1867_enabled)) { ++ if (!PS(rfc1867_enabled) || 1) { + return retval; + } + +diff --git a/main/SAPI.c b/main/SAPI.c +index 01383357..17afa0e0 100644 +--- a/main/SAPI.c ++++ b/main/SAPI.c +@@ -515,18 +515,23 @@ SAPI_API void sapi_deactivate(void) + } + if (SG(request_info).auth_user) { + efree(SG(request_info).auth_user); ++ SG(request_info).auth_user = NULL; + } + if (SG(request_info).auth_password) { + efree(SG(request_info).auth_password); ++ SG(request_info).auth_password = NULL; + } + if (SG(request_info).auth_digest) { + efree(SG(request_info).auth_digest); ++ SG(request_info).auth_digest = NULL; + } + if (SG(request_info).content_type_dup) { + efree(SG(request_info).content_type_dup); ++ SG(request_info).content_type_dup = NULL; + } + if (SG(request_info).current_user) { + efree(SG(request_info).current_user); ++ SG(request_info).current_user = NULL; + } + if (sapi_module.deactivate) { + sapi_module.deactivate(); +diff --git a/main/main.c b/main/main.c +index 0cfdb913..92c19e46 100644 +--- a/main/main.c ++++ b/main/main.c +@@ -1895,6 +1895,8 @@ void php_request_shutdown(void *dummy) + + for (i=0; i +Date: Fri, 22 Nov 2024 15:24:16 +0100 +Subject: backport ZSTR_MAX_LEN + +(cherry picked from commit 37056ad634d9c44bac0d6c8e730eafaec1344840) +--- + Zend/zend_string.h | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/Zend/zend_string.h b/Zend/zend_string.h +index 784b88e..5f7a9ea 100644 +--- a/Zend/zend_string.h ++++ b/Zend/zend_string.h +@@ -74,6 +74,9 @@ END_EXTERN_C() + + #define _ZSTR_STRUCT_SIZE(len) (_ZSTR_HEADER_SIZE + len + 1) + ++#define ZSTR_MAX_OVERHEAD (ZEND_MM_ALIGNED_SIZE(_ZSTR_HEADER_SIZE + 1)) ++#define ZSTR_MAX_LEN (SIZE_MAX - ZSTR_MAX_OVERHEAD) ++ + #define ZSTR_ALLOCA_ALLOC(str, _len, use_heap) do { \ + (str) = (zend_string *)do_alloca(ZEND_MM_ALIGNED_SIZE_EX(_ZSTR_STRUCT_SIZE(_len), 8), (use_heap)); \ + GC_REFCOUNT(str) = 1; \ diff --git a/runtime/patches/php-7.3-security.patch b/runtime/patches/php-7.3-security.patch new file mode 100644 index 0000000..5504293 --- /dev/null +++ b/runtime/patches/php-7.3-security.patch @@ -0,0 +1,912 @@ +From: Arnaud Le Blanc +Date: Sun, 18 Oct 2026 20:09:54 +0200 +Subject: Avoid state corruption via bailout + +Minimal mitigation for EOL version. + +Fix GHSA-w8hw-w9fx-j79w (CVE-2026-109618) +Fix GHSA-6wmf-4rv5-p3rp (CVE-2026-109619) + +Backported from the PHP 7.4 version: +- shutdown_executor() frees the object store before the error handlers, + so the fast shutdown resets are done just before + zend_objects_store_free_object_storage(). +- "|| 1" instead of "|| true" in the session upload progress callback + (no stdbool.h). +- The max_multipart_body_parts hunk of the 7.4 patch is left out, the + code is already there. + +Co-authored-by: Ilija Tovilo +--- + Zend/zend_API.h | 1 + + Zend/zend_alloc.c | 68 +++++++++++++++++++-------- + Zend/zend_alloc.h | 2 + + Zend/zend_execute_API.c | 15 ++++++ + Zend/zend_hash.c | 13 +++-- + Zend/zend_hash.h | 1 + + Zend/zend_llist.c | 2 + + Zend/zend_multiply.h | 4 +- + Zend/zend_strtod.c | 4 +- + Zend/zend_types.h | 26 +++++----- + Zend/zend_vm_def.h | 12 +++++ + Zend/zend_vm_execute.h | 102 ++++++++++++++++++++++++++++++++++++++++ + ext/session/session.c | 2 +- + main/SAPI.c | 5 ++ + main/main.c | 5 ++ + main/php_variables.c | 8 ++-- + main/rfc1867.c | 29 ++++++++---- + 17 files changed, 248 insertions(+), 51 deletions(-) + +diff --git a/Zend/zend_API.h b/Zend/zend_API.h +index 3c134f44..67942e39 100644 +--- a/Zend/zend_API.h ++++ b/Zend/zend_API.h +@@ -376,6 +376,7 @@ ZEND_API char *zend_get_type_by_const(int type); + + #define array_init(arg) ZVAL_ARR((arg), zend_new_array(0)) + #define array_init_size(arg, size) ZVAL_ARR((arg), zend_new_array(size)) ++#define array_init_singleton(arg) ZVAL_ARR((arg), zend_new_array_singleton()) + ZEND_API int object_init(zval *arg); + ZEND_API int object_init_ex(zval *arg, zend_class_entry *ce); + ZEND_API int object_and_properties_init(zval *arg, zend_class_entry *ce, HashTable *properties); +diff --git a/Zend/zend_alloc.c b/Zend/zend_alloc.c +index 25216898..126aa124 100644 +--- a/Zend/zend_alloc.c ++++ b/Zend/zend_alloc.c +@@ -57,6 +57,7 @@ + #include "zend_operators.h" + #include "zend_multiply.h" + #include "zend_bitset.h" ++#include "zend_execute.h" + + #ifdef HAVE_SIGNAL_H + # include +@@ -358,7 +359,42 @@ static ZEND_COLD ZEND_NORETURN void zend_mm_panic(const char *message) + #if ZEND_DEBUG && defined(HAVE_KILL) && defined(HAVE_GETPID) + kill(getpid(), SIGSEGV); + #endif +- exit(1); ++ _exit(1); ++} ++ ++ZEND_API ZEND_COLD ZEND_NORETURN void zend_mm_safe_error_ex(const char *format, ...) ++{ ++ zend_string *script_filename = NULL; ++ uint32_t script_lineno = 0; ++ ++ if (zend_is_executing()) { ++ script_filename = zend_get_executed_filename_ex(); ++ script_lineno = zend_get_executed_lineno(); ++ } else if (zend_is_compiling()) { ++ script_filename = zend_get_compiled_filename(); ++ script_lineno = zend_get_compiled_lineno(); ++ } ++ ++ va_list args; ++ va_start(args, format); ++ ++ char buf[1024]; ++ vsnprintf(buf, sizeof(buf), format, args); ++ ++ va_end(args); ++ ++ fprintf(stderr, ++ "\nFatal error: %s in %s on line %d\n", ++ buf, ++ script_filename ? ZSTR_VAL(script_filename) : "Unknown", ++ script_lineno); ++ ++ /* See http://support.microsoft.com/kb/190351 */ ++# ifdef ZEND_WIN32 ++ fflush(stderr); ++# endif ++ ++ _exit(1); + } + + static ZEND_COLD ZEND_NORETURN void zend_mm_safe_error(zend_mm_heap *heap, +@@ -370,22 +406,14 @@ static ZEND_COLD ZEND_NORETURN void zend_mm_safe_error(zend_mm_heap *heap, + #endif + size_t size) + { ++ (void) heap; + +- heap->overflow = 1; +- zend_try { +- zend_error_noreturn(E_ERROR, +- format, +- limit, ++ zend_mm_safe_error_ex(format, limit, + #if ZEND_DEBUG +- filename, +- lineno, ++ filename, ++ lineno, + #endif +- size); +- } zend_catch { +- } zend_end_try(); +- heap->overflow = 0; +- zend_bailout(); +- exit(1); ++ size); + } + + #ifdef _WIN32 +@@ -1352,7 +1380,7 @@ static zend_always_inline void *zend_mm_alloc_heap(zend_mm_heap *heap, size_t si + size = MAX(size, 1); + size = ZEND_MM_ALIGNED_SIZE(size) + ZEND_MM_ALIGNED_SIZE(sizeof(zend_mm_debug_info)); + if (UNEXPECTED(size < real_size)) { +- zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%zu + %zu)", ZEND_MM_ALIGNED_SIZE(real_size), ZEND_MM_ALIGNED_SIZE(sizeof(zend_mm_debug_info))); ++ zend_mm_safe_error_ex("Possible integer overflow in memory allocation (%zu + %zu)", ZEND_MM_ALIGNED_SIZE(real_size), ZEND_MM_ALIGNED_SIZE(sizeof(zend_mm_debug_info))); + return NULL; + } + #endif +@@ -1800,7 +1828,7 @@ static void *zend_mm_alloc_huge(zend_mm_heap *heap, size_t size ZEND_FILE_LINE_D + void *ptr; + + if (UNEXPECTED(new_size < size)) { +- zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%zu + %zu)", size, alignment); ++ zend_mm_safe_error_ex("Possible integer overflow in memory allocation (%zu + %zu)", size, alignment); + } + + #if ZEND_MM_LIMIT +@@ -2596,7 +2624,7 @@ ZEND_API char* ZEND_FASTCALL _estrdup(const char *s ZEND_FILE_LINE_DC ZEND_FILE_ + + length = strlen(s); + if (UNEXPECTED(length + 1 == 0)) { +- zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (1 * %zu + 1)", length); ++ zend_mm_safe_error_ex("Possible integer overflow in memory allocation (1 * %zu + 1)", length); + } + p = (char *) _emalloc(length + 1 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC); + memcpy(p, s, length+1); +@@ -2608,7 +2636,7 @@ ZEND_API char* ZEND_FASTCALL _estrndup(const char *s, size_t length ZEND_FILE_LI + char *p; + + if (UNEXPECTED(length + 1 == 0)) { +- zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (1 * %zu + 1)", length); ++ zend_mm_safe_error_ex("Possible integer overflow in memory allocation (1 * %zu + 1)", length); + } + p = (char *) _emalloc(length + 1 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC); + memcpy(p, s, length); +@@ -2622,7 +2650,7 @@ ZEND_API char* ZEND_FASTCALL zend_strndup(const char *s, size_t length) + char *p; + + if (UNEXPECTED(length + 1 == 0)) { +- zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (1 * %zu + 1)", length); ++ zend_mm_safe_error_ex("Possible integer overflow in memory allocation (1 * %zu + 1)", length); + } + p = (char *) malloc(length + 1); + if (UNEXPECTED(p == NULL)) { +@@ -2901,7 +2929,7 @@ ZEND_API zend_mm_heap *zend_mm_startup_ex(const zend_mm_handlers *handlers, void + static ZEND_COLD ZEND_NORETURN void zend_out_of_memory(void) + { + fprintf(stderr, "Out of memory\n"); +- exit(1); ++ _exit(1); + } + + ZEND_API void * __zend_malloc(size_t len) +diff --git a/Zend/zend_alloc.h b/Zend/zend_alloc.h +index b3986ab9..992fa225 100644 +--- a/Zend/zend_alloc.h ++++ b/Zend/zend_alloc.h +@@ -397,6 +397,8 @@ static void apc_init_heap(void) + + */ + ++ZEND_API ZEND_COLD ZEND_NORETURN void zend_mm_safe_error_ex(const char *format, ...); ++ + END_EXTERN_C() + + #endif +diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c +index 6eb9dfac..65e66fc8 100644 +--- a/Zend/zend_execute_API.c ++++ b/Zend/zend_execute_API.c +@@ -265,8 +265,21 @@ void shutdown_executor(void) /* {{{ */ + zend_close_rsrc_list(&EG(regular_list)); + } zend_end_try(); + ++ if (fast_shutdown) { ++ /* may be used by zend_error before init_executor */ ++ ZVAL_UNDEF(&EG(user_error_handler)); ++ ZVAL_UNDEF(&EG(user_exception_handler)); ++ memset(&EG(user_error_handlers_error_reporting), 0, sizeof(EG(user_error_handlers_error_reporting))); ++ memset(&EG(user_error_handlers), 0, sizeof(EG(user_error_handlers))); ++ memset(&EG(user_exception_handlers), 0, sizeof(EG(user_exception_handlers))); ++ } ++ + zend_objects_store_free_object_storage(&EG(objects_store), fast_shutdown); + ++ /* may be used by zend_error before init_executor */ ++ EG(error_handling) = EH_NORMAL; ++ EG(exception) = NULL; ++ + /* All resources and objects are destroyed. */ + /* No PHP callback functions may be called after this point. */ + EG(active) = 0; +@@ -285,6 +298,8 @@ void shutdown_executor(void) /* {{{ */ + zend_hash_discard(EG(function_table), EG(persistent_functions_count)); + zend_hash_discard(EG(class_table), EG(persistent_classes_count)); + zend_cleanup_internal_classes(); ++ EG(objects_store).object_buckets = NULL; ++ EG(objects_store).top = 1; + } else { + zend_hash_graceful_reverse_destroy(&EG(symbol_table)); + +diff --git a/Zend/zend_hash.c b/Zend/zend_hash.c +index 7ba4f32c..f228f335 100644 +--- a/Zend/zend_hash.c ++++ b/Zend/zend_hash.c +@@ -93,7 +93,7 @@ static zend_always_inline uint32_t zend_hash_check_size(uint32_t nSize) + if (nSize <= HT_MIN_SIZE) { + return HT_MIN_SIZE; + } else if (UNEXPECTED(nSize >= HT_MAX_SIZE)) { +- zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%u * %zu + %zu)", nSize, sizeof(Bucket), sizeof(Bucket)); ++ zend_mm_safe_error_ex("Possible integer overflow in memory allocation (%u * %zu + %zu)", nSize, sizeof(Bucket), sizeof(Bucket)); + } + + #if defined(ZEND_WIN32) +@@ -219,6 +219,13 @@ ZEND_API HashTable* ZEND_FASTCALL _zend_new_array_0(void) + return ht; + } + ++ZEND_API HashTable* ZEND_FASTCALL zend_new_array_singleton(void) ++{ ++ HashTable *ht = _zend_new_array_0(); ++ ht->nTableSize = 1; ++ return ht; ++} ++ + ZEND_API HashTable* ZEND_FASTCALL _zend_new_array(uint32_t nSize) + { + HashTable *ht = emalloc(sizeof(HashTable)); +@@ -230,7 +237,7 @@ static void ZEND_FASTCALL zend_hash_packed_grow(HashTable *ht) + { + HT_ASSERT_RC1(ht); + if (ht->nTableSize >= HT_MAX_SIZE) { +- zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%u * %zu + %zu)", ht->nTableSize * 2, sizeof(Bucket), sizeof(Bucket)); ++ zend_mm_safe_error_ex("Possible integer overflow in memory allocation (%u * %zu + %zu)", ht->nTableSize * 2, sizeof(Bucket), sizeof(Bucket)); + } + ht->nTableSize += ht->nTableSize; + HT_SET_DATA_ADDR(ht, perealloc2(HT_GET_DATA_ADDR(ht), HT_SIZE_EX(ht->nTableSize, HT_MIN_MASK), HT_USED_SIZE(ht), GC_FLAGS(ht) & IS_ARRAY_PERSISTENT)); +@@ -1041,7 +1048,7 @@ static void ZEND_FASTCALL zend_hash_do_resize(HashTable *ht) + pefree(old_data, GC_FLAGS(ht) & IS_ARRAY_PERSISTENT); + zend_hash_rehash(ht); + } else { +- zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%u * %zu + %zu)", ht->nTableSize * 2, sizeof(Bucket) + sizeof(uint32_t), sizeof(Bucket)); ++ zend_mm_safe_error_ex("Possible integer overflow in memory allocation (%u * %zu + %zu)", ht->nTableSize * 2, sizeof(Bucket) + sizeof(uint32_t), sizeof(Bucket)); + } + } + +diff --git a/Zend/zend_hash.h b/Zend/zend_hash.h +index 2c295adc..51dc4c5e 100644 +--- a/Zend/zend_hash.h ++++ b/Zend/zend_hash.h +@@ -276,6 +276,7 @@ ZEND_API int ZEND_FASTCALL zend_hash_rehash(HashTable *ht); + #endif + + ZEND_API HashTable* ZEND_FASTCALL _zend_new_array_0(void); ++ZEND_API HashTable* ZEND_FASTCALL zend_new_array_singleton(void); + ZEND_API HashTable* ZEND_FASTCALL _zend_new_array(uint32_t size); + ZEND_API uint32_t zend_array_count(HashTable *ht); + ZEND_API HashTable* ZEND_FASTCALL zend_array_dup(HashTable *source); +diff --git a/Zend/zend_llist.c b/Zend/zend_llist.c +index ea5e2cae..f45ddda9 100644 +--- a/Zend/zend_llist.c ++++ b/Zend/zend_llist.c +@@ -112,6 +112,8 @@ ZEND_API void zend_llist_destroy(zend_llist *l) + current = next; + } + ++ l->head = NULL; ++ l->tail = NULL; + l->count = 0; + } + +diff --git a/Zend/zend_multiply.h b/Zend/zend_multiply.h +index 1ec1af06..ee2fd8df 100644 +--- a/Zend/zend_multiply.h ++++ b/Zend/zend_multiply.h +@@ -321,7 +321,7 @@ static zend_always_inline size_t zend_safe_address_guarded(size_t nmemb, size_t + size_t ret = zend_safe_address(nmemb, size, offset, &overflow); + + if (UNEXPECTED(overflow)) { +- zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%zu * %zu + %zu)", nmemb, size, offset); ++ zend_mm_safe_error_ex("Possible integer overflow in memory allocation (%zu * %zu + %zu)", nmemb, size, offset); + return 0; + } + return ret; +@@ -334,7 +334,7 @@ static zend_always_inline size_t zend_safe_addmult(size_t nmemb, size_t size, si + size_t ret = zend_safe_address(nmemb, size, offset, &overflow); + + if (UNEXPECTED(overflow)) { +- zend_error_noreturn(E_ERROR, "Possible integer overflow in %s (%zu * %zu + %zu)", message, nmemb, size, offset); ++ zend_mm_safe_error_ex("Possible integer overflow in %s (%zu * %zu + %zu)", message, nmemb, size, offset); + return 0; + } + return ret; +diff --git a/Zend/zend_strtod.c b/Zend/zend_strtod.c +index 3aa99f8d..01c1779d 100644 +--- a/Zend/zend_strtod.c ++++ b/Zend/zend_strtod.c +@@ -600,7 +600,7 @@ Balloc + rv = (Bigint *)MALLOC(sizeof(Bigint) + (x-1)*sizeof(ULong)); + if (!rv) { + FREE_DTOA_LOCK(0); +- zend_error_noreturn(E_ERROR, "Balloc() failed to allocate memory"); ++ zend_mm_safe_error_ex("Balloc() failed to allocate memory"); + } + #else + len = (sizeof(Bigint) + (x-1)*sizeof(ULong) + sizeof(double) - 1) +@@ -613,7 +613,7 @@ Balloc + rv = (Bigint*)MALLOC(len*sizeof(double)); + if (!rv) { + FREE_DTOA_LOCK(0); +- zend_error_noreturn(E_ERROR, "Balloc() failed to allocate memory"); ++ zend_mm_safe_error_ex("Balloc() failed to allocate memory"); + } + #endif + rv->k = k; +diff --git a/Zend/zend_types.h b/Zend/zend_types.h +index 4250aabd..fd7e5d6a 100644 +--- a/Zend/zend_types.h ++++ b/Zend/zend_types.h +@@ -317,17 +317,21 @@ struct _zend_array { + # define HT_HASH_RESET(ht) do { \ + char *p = (char*)&HT_HASH(ht, (ht)->nTableMask); \ + size_t size = HT_HASH_SIZE((ht)->nTableMask); \ +- __m128i xmm0 = _mm_setzero_si128(); \ +- xmm0 = _mm_cmpeq_epi8(xmm0, xmm0); \ +- ZEND_ASSERT(size >= 64 && ((size & 0x3f) == 0)); \ +- do { \ +- _mm_storeu_si128((__m128i*)p, xmm0); \ +- _mm_storeu_si128((__m128i*)(p+16), xmm0); \ +- _mm_storeu_si128((__m128i*)(p+32), xmm0); \ +- _mm_storeu_si128((__m128i*)(p+48), xmm0); \ +- p += 64; \ +- size -= 64; \ +- } while (size != 0); \ ++ if (UNEXPECTED(size < 64)) { \ ++ memset(p, HT_INVALID_IDX, size); \ ++ } else { \ ++ __m128i xmm0 = _mm_setzero_si128(); \ ++ xmm0 = _mm_cmpeq_epi8(xmm0, xmm0); \ ++ ZEND_ASSERT(size >= 64 && ((size & 0x3f) == 0)); \ ++ do { \ ++ _mm_storeu_si128((__m128i*)p, xmm0); \ ++ _mm_storeu_si128((__m128i*)(p+16), xmm0); \ ++ _mm_storeu_si128((__m128i*)(p+32), xmm0); \ ++ _mm_storeu_si128((__m128i*)(p+48), xmm0); \ ++ p += 64; \ ++ size -= 64; \ ++ } while (size != 0); \ ++ } \ + } while (0) + #else + # define HT_HASH_RESET(ht) \ +diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h +index 1b4eb572..da46a635 100644 +--- a/Zend/zend_vm_def.h ++++ b/Zend/zend_vm_def.h +@@ -320,11 +320,17 @@ ZEND_VM_HANDLER(8, ZEND_CONCAT, CONST|TMPVAR|CV, CONST|TMPVAR|CV, SPEC(NO_CONST_ + !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { + size_t len = ZSTR_LEN(op1_str); + ++ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + ZVAL_NEW_STR(EX_VAR(opline->result.var), str); + FREE_OP2(); + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -2744,11 +2750,17 @@ ZEND_VM_COLD_CONSTCONST_HANDLER(53, ZEND_FAST_CONCAT, CONST|TMPVAR|CV, CONST|TMP + !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { + size_t len = ZSTR_LEN(op1_str); + ++ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + ZVAL_NEW_STR(EX_VAR(opline->result.var), str); + FREE_OP2(); + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h +index be8b2b3a..ce447cb9 100644 +--- a/Zend/zend_vm_execute.h ++++ b/Zend/zend_vm_execute.h +@@ -4968,11 +4968,17 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_ + !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { + size_t len = ZSTR_LEN(op1_str); + ++ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + ZVAL_NEW_STR(EX_VAR(opline->result.var), str); + + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -6679,11 +6685,17 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_CONST_TMPVAR_HANDL + !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { + size_t len = ZSTR_LEN(op1_str); + ++ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + ZVAL_NEW_STR(EX_VAR(opline->result.var), str); + zval_ptr_dtor_nogc(free_op2); + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -7150,11 +7162,17 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CONST_TMPVAR_ + !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { + size_t len = ZSTR_LEN(op1_str); + ++ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + ZVAL_NEW_STR(EX_VAR(opline->result.var), str); + zval_ptr_dtor_nogc(free_op2); + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -9774,11 +9792,17 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_CONST_CV_HANDLER(Z + !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { + size_t len = ZSTR_LEN(op1_str); + ++ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + ZVAL_NEW_STR(EX_VAR(opline->result.var), str); + + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -10243,11 +10267,17 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CONST_CV_HAND + !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { + size_t len = ZSTR_LEN(op1_str); + ++ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + ZVAL_NEW_STR(EX_VAR(opline->result.var), str); + + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -12967,11 +12997,17 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_TMPVAR_CONST_HANDL + !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { + size_t len = ZSTR_LEN(op1_str); + ++ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + ZVAL_NEW_STR(EX_VAR(opline->result.var), str); + + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -13732,11 +13768,17 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_TMPVAR_CONST_ + !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { + size_t len = ZSTR_LEN(op1_str); + ++ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + ZVAL_NEW_STR(EX_VAR(opline->result.var), str); + + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -14705,11 +14747,17 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_TMPVAR_TMPVAR_HAND + !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { + size_t len = ZSTR_LEN(op1_str); + ++ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + ZVAL_NEW_STR(EX_VAR(opline->result.var), str); + zval_ptr_dtor_nogc(free_op2); + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -15346,11 +15394,17 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_TMPVAR_TMPVAR + !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { + size_t len = ZSTR_LEN(op1_str); + ++ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + ZVAL_NEW_STR(EX_VAR(opline->result.var), str); + zval_ptr_dtor_nogc(free_op2); + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -16800,11 +16854,17 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_TMPVAR_CV_HANDLER( + !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { + size_t len = ZSTR_LEN(op1_str); + ++ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + ZVAL_NEW_STR(EX_VAR(opline->result.var), str); + + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -17227,11 +17287,17 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_TMPVAR_CV_HAN + !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { + size_t len = ZSTR_LEN(op1_str); + ++ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + ZVAL_NEW_STR(EX_VAR(opline->result.var), str); + + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -38581,11 +38647,17 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_CV_CONST_HANDLER(Z + !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { + size_t len = ZSTR_LEN(op1_str); + ++ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + ZVAL_NEW_STR(EX_VAR(opline->result.var), str); + + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -41090,11 +41162,17 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CV_CONST_HAND + !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { + size_t len = ZSTR_LEN(op1_str); + ++ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + ZVAL_NEW_STR(EX_VAR(opline->result.var), str); + + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -42559,11 +42637,17 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_CV_TMPVAR_HANDLER( + !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { + size_t len = ZSTR_LEN(op1_str); + ++ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + ZVAL_NEW_STR(EX_VAR(opline->result.var), str); + zval_ptr_dtor_nogc(free_op2); + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -44857,11 +44941,17 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CV_TMPVAR_HAN + !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { + size_t len = ZSTR_LEN(op1_str); + ++ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + ZVAL_NEW_STR(EX_VAR(opline->result.var), str); + zval_ptr_dtor_nogc(free_op2); + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -48227,11 +48317,17 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_CV_CV_HANDLER(ZEND + !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { + size_t len = ZSTR_LEN(op1_str); + ++ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + ZVAL_NEW_STR(EX_VAR(opline->result.var), str); + + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -50659,11 +50755,17 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CV_CV_HANDLER + !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { + size_t len = ZSTR_LEN(op1_str); + ++ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + ZVAL_NEW_STR(EX_VAR(opline->result.var), str); + + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +diff --git a/ext/session/session.c b/ext/session/session.c +index 8fad988d..1c328815 100644 +--- a/ext/session/session.c ++++ b/ext/session/session.c +@@ -3160,7 +3160,7 @@ static int php_session_rfc1867_callback(unsigned int event, void *event_data, vo + if (php_session_rfc1867_orig_callback) { + retval = php_session_rfc1867_orig_callback(event, event_data, extra); + } +- if (!PS(rfc1867_enabled)) { ++ if (!PS(rfc1867_enabled) || 1) { + return retval; + } + +diff --git a/main/SAPI.c b/main/SAPI.c +index afb0c772..6749184e 100644 +--- a/main/SAPI.c ++++ b/main/SAPI.c +@@ -513,18 +513,23 @@ SAPI_API void sapi_deactivate(void) + } + if (SG(request_info).auth_user) { + efree(SG(request_info).auth_user); ++ SG(request_info).auth_user = NULL; + } + if (SG(request_info).auth_password) { + efree(SG(request_info).auth_password); ++ SG(request_info).auth_password = NULL; + } + if (SG(request_info).auth_digest) { + efree(SG(request_info).auth_digest); ++ SG(request_info).auth_digest = NULL; + } + if (SG(request_info).content_type_dup) { + efree(SG(request_info).content_type_dup); ++ SG(request_info).content_type_dup = NULL; + } + if (SG(request_info).current_user) { + efree(SG(request_info).current_user); ++ SG(request_info).current_user = NULL; + } + if (sapi_module.deactivate) { + sapi_module.deactivate(); +diff --git a/main/main.c b/main/main.c +index c3939b3c..6e38959a 100644 +--- a/main/main.c ++++ b/main/main.c +@@ -1919,6 +1919,8 @@ void php_request_shutdown(void *dummy) + + for (i=0; i +Date: Fri, 22 Nov 2024 15:24:16 +0100 +Subject: backport ZSTR_MAX_LEN + +--- + Zend/zend_string.h | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/Zend/zend_string.h b/Zend/zend_string.h +index 396b63b..8ef979f 100644 +--- a/Zend/zend_string.h ++++ b/Zend/zend_string.h +@@ -76,6 +76,9 @@ END_EXTERN_C() + + #define _ZSTR_STRUCT_SIZE(len) (_ZSTR_HEADER_SIZE + len + 1) + ++#define ZSTR_MAX_OVERHEAD (ZEND_MM_ALIGNED_SIZE(_ZSTR_HEADER_SIZE + 1)) ++#define ZSTR_MAX_LEN (SIZE_MAX - ZSTR_MAX_OVERHEAD) ++ + #define ZSTR_ALLOCA_ALLOC(str, _len, use_heap) do { \ + (str) = (zend_string *)do_alloca(ZEND_MM_ALIGNED_SIZE_EX(_ZSTR_STRUCT_SIZE(_len), 8), (use_heap)); \ + GC_SET_REFCOUNT(str, 1); \ diff --git a/runtime/patches/php-7.4-security.patch b/runtime/patches/php-7.4-security.patch new file mode 100644 index 0000000..158f865 --- /dev/null +++ b/runtime/patches/php-7.4-security.patch @@ -0,0 +1,973 @@ +From 712e60f9edfd03f0960fc4fc3c2c375f42b90aa2 Mon Sep 17 00:00:00 2001 +From: Arnaud Le Blanc +Date: Sun, 18 Oct 2026 20:09:54 +0200 +Subject: [PATCH] Avoid state corruption via bailout + +Minimal mitigation for EOL version. + +Fix GHSA-w8hw-w9fx-j79w (CVE-2026-109618) +Fix GHSA-6wmf-4rv5-p3rp (CVE-2026-109619) + +Co-authored-by: Ilija Tovilo +--- + Zend/zend_API.h | 1 + + Zend/zend_alloc.c | 68 ++++++++++++++++++++--------- + Zend/zend_alloc.h | 2 + + Zend/zend_execute_API.c | 13 ++++++ + Zend/zend_hash.c | 13 ++++-- + Zend/zend_hash.h | 1 + + Zend/zend_llist.c | 2 + + Zend/zend_multiply.h | 4 +- + Zend/zend_strtod.c | 4 +- + Zend/zend_types.h | 26 +++++++----- + Zend/zend_vm_def.h | 11 ++++- + Zend/zend_vm_execute.h | 94 +++++++++++++++++++++++++++++++++++++---- + ext/session/session.c | 2 +- + main/SAPI.c | 5 +++ + main/main.c | 6 +++ + main/php_variables.c | 8 ++-- + main/rfc1867.c | 39 ++++++++++++++--- + 17 files changed, 240 insertions(+), 59 deletions(-) + +diff --git a/Zend/zend_API.h b/Zend/zend_API.h +index 2a3b582902f3..26f7726bd8cc 100644 +--- a/Zend/zend_API.h ++++ b/Zend/zend_API.h +@@ -380,6 +380,7 @@ ZEND_API char *zend_get_type_by_const(int type); + + #define array_init(arg) ZVAL_ARR((arg), zend_new_array(0)) + #define array_init_size(arg, size) ZVAL_ARR((arg), zend_new_array(size)) ++#define array_init_singleton(arg) ZVAL_ARR((arg), zend_new_array_singleton()) + ZEND_API int object_init(zval *arg); + ZEND_API int object_init_ex(zval *arg, zend_class_entry *ce); + ZEND_API int object_and_properties_init(zval *arg, zend_class_entry *ce, HashTable *properties); +diff --git a/Zend/zend_alloc.c b/Zend/zend_alloc.c +index 3a33e5441c70..be9b975426be 100644 +--- a/Zend/zend_alloc.c ++++ b/Zend/zend_alloc.c +@@ -57,6 +57,7 @@ + #include "zend_operators.h" + #include "zend_multiply.h" + #include "zend_bitset.h" ++#include "zend_execute.h" + #include + + #ifdef HAVE_UNISTD_H +@@ -363,7 +364,42 @@ static ZEND_COLD ZEND_NORETURN void zend_mm_panic(const char *message) + #if ZEND_DEBUG && defined(HAVE_KILL) && defined(HAVE_GETPID) + kill(getpid(), SIGSEGV); + #endif +- exit(1); ++ _exit(1); ++} ++ ++ZEND_API ZEND_COLD ZEND_NORETURN void zend_mm_safe_error_ex(const char *format, ...) ++{ ++ zend_string *script_filename = NULL; ++ uint32_t script_lineno = 0; ++ ++ if (zend_is_executing()) { ++ script_filename = zend_get_executed_filename_ex(); ++ script_lineno = zend_get_executed_lineno(); ++ } else if (zend_is_compiling()) { ++ script_filename = zend_get_compiled_filename(); ++ script_lineno = zend_get_compiled_lineno(); ++ } ++ ++ va_list args; ++ va_start(args, format); ++ ++ char buf[1024]; ++ vsnprintf(buf, sizeof(buf), format, args); ++ ++ va_end(args); ++ ++ fprintf(stderr, ++ "\nFatal error: %s in %s on line %d\n", ++ buf, ++ script_filename ? ZSTR_VAL(script_filename) : "Unknown", ++ script_lineno); ++ ++ /* See http://support.microsoft.com/kb/190351 */ ++# ifdef ZEND_WIN32 ++ fflush(stderr); ++# endif ++ ++ _exit(1); + } + + static ZEND_COLD ZEND_NORETURN void zend_mm_safe_error(zend_mm_heap *heap, +@@ -375,22 +411,14 @@ static ZEND_COLD ZEND_NORETURN void zend_mm_safe_error(zend_mm_heap *heap, + #endif + size_t size) + { ++ (void) heap; + +- heap->overflow = 1; +- zend_try { +- zend_error_noreturn(E_ERROR, +- format, +- limit, ++ zend_mm_safe_error_ex(format, limit, + #if ZEND_DEBUG +- filename, +- lineno, ++ filename, ++ lineno, + #endif +- size); +- } zend_catch { +- } zend_end_try(); +- heap->overflow = 0; +- zend_bailout(); +- exit(1); ++ size); + } + + #ifdef _WIN32 +@@ -1318,7 +1346,7 @@ static zend_always_inline void *zend_mm_alloc_heap(zend_mm_heap *heap, size_t si + size = MAX(size, 1); + size = ZEND_MM_ALIGNED_SIZE(size) + ZEND_MM_ALIGNED_SIZE(sizeof(zend_mm_debug_info)); + if (UNEXPECTED(size < real_size)) { +- zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%zu + %zu)", ZEND_MM_ALIGNED_SIZE(real_size), ZEND_MM_ALIGNED_SIZE(sizeof(zend_mm_debug_info))); ++ zend_mm_safe_error_ex("Possible integer overflow in memory allocation (%zu + %zu)", ZEND_MM_ALIGNED_SIZE(real_size), ZEND_MM_ALIGNED_SIZE(sizeof(zend_mm_debug_info))); + return NULL; + } + #endif +@@ -1762,7 +1790,7 @@ static void *zend_mm_alloc_huge(zend_mm_heap *heap, size_t size ZEND_FILE_LINE_D + void *ptr; + + if (UNEXPECTED(new_size < size)) { +- zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%zu + %zu)", size, alignment); ++ zend_mm_safe_error_ex("Possible integer overflow in memory allocation (%zu + %zu)", size, alignment); + } + + #if ZEND_MM_LIMIT +@@ -2617,7 +2645,7 @@ ZEND_API char* ZEND_FASTCALL _estrdup(const char *s ZEND_FILE_LINE_DC ZEND_FILE_ + + length = strlen(s); + if (UNEXPECTED(length + 1 == 0)) { +- zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (1 * %zu + 1)", length); ++ zend_mm_safe_error_ex("Possible integer overflow in memory allocation (1 * %zu + 1)", length); + } + p = (char *) _emalloc(length + 1 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC); + memcpy(p, s, length+1); +@@ -2629,7 +2657,7 @@ ZEND_API char* ZEND_FASTCALL _estrndup(const char *s, size_t length ZEND_FILE_LI + char *p; + + if (UNEXPECTED(length + 1 == 0)) { +- zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (1 * %zu + 1)", length); ++ zend_mm_safe_error_ex("Possible integer overflow in memory allocation (1 * %zu + 1)", length); + } + p = (char *) _emalloc(length + 1 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC); + memcpy(p, s, length); +@@ -2643,7 +2671,7 @@ ZEND_API char* ZEND_FASTCALL zend_strndup(const char *s, size_t length) + char *p; + + if (UNEXPECTED(length + 1 == 0)) { +- zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (1 * %zu + 1)", length); ++ zend_mm_safe_error_ex("Possible integer overflow in memory allocation (1 * %zu + 1)", length); + } + p = (char *) malloc(length + 1); + if (UNEXPECTED(p == NULL)) { +@@ -2974,7 +3002,7 @@ ZEND_API zend_mm_heap *zend_mm_startup_ex(const zend_mm_handlers *handlers, void + static ZEND_COLD ZEND_NORETURN void zend_out_of_memory(void) + { + fprintf(stderr, "Out of memory\n"); +- exit(1); ++ _exit(1); + } + + ZEND_API void * __zend_malloc(size_t len) +diff --git a/Zend/zend_alloc.h b/Zend/zend_alloc.h +index 8bb854328dbd..2ed2ed8b3adf 100644 +--- a/Zend/zend_alloc.h ++++ b/Zend/zend_alloc.h +@@ -402,6 +402,8 @@ static void apc_init_heap(void) + size_t zend_mm_globals_size(void); + #endif + ++ZEND_API ZEND_COLD ZEND_NORETURN void zend_mm_safe_error_ex(const char *format, ...); ++ + END_EXTERN_C() + + #endif +diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c +index f4f0fa14f1d3..724b6e5cc414 100644 +--- a/Zend/zend_execute_API.c ++++ b/Zend/zend_execute_API.c +@@ -337,10 +337,21 @@ void shutdown_executor(void) /* {{{ */ + gc_collect_cycles(); + } + #endif ++ } else { ++ /* may be used by zend_error_zstr_at before init_executor */ ++ ZVAL_UNDEF(&EG(user_error_handler)); ++ ZVAL_UNDEF(&EG(user_exception_handler)); ++ memset(&EG(user_error_handlers_error_reporting), 0, sizeof(EG(user_error_handlers_error_reporting))); ++ memset(&EG(user_error_handlers), 0, sizeof(EG(user_error_handlers))); ++ memset(&EG(user_exception_handlers), 0, sizeof(EG(user_exception_handlers))); + } + + zend_objects_store_free_object_storage(&EG(objects_store), fast_shutdown); + ++ /* may be used by zend_error_zstr_at before init_executor */ ++ EG(error_handling) = EH_NORMAL; ++ EG(exception) = NULL; ++ + zend_weakrefs_shutdown(); + + zend_try { +@@ -357,6 +368,8 @@ void shutdown_executor(void) /* {{{ */ + zend_hash_discard(EG(function_table), EG(persistent_functions_count)); + zend_hash_discard(EG(class_table), EG(persistent_classes_count)); + zend_cleanup_internal_classes(); ++ EG(objects_store).object_buckets = NULL; ++ EG(objects_store).top = 1; + } else { + zend_vm_stack_destroy(); + +diff --git a/Zend/zend_hash.c b/Zend/zend_hash.c +index da150bd7984c..ef3d301db15e 100644 +--- a/Zend/zend_hash.c ++++ b/Zend/zend_hash.c +@@ -97,7 +97,7 @@ static zend_always_inline uint32_t zend_hash_check_size(uint32_t nSize) + if (nSize <= HT_MIN_SIZE) { + return HT_MIN_SIZE; + } else if (UNEXPECTED(nSize >= HT_MAX_SIZE)) { +- zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%u * %zu + %zu)", nSize, sizeof(Bucket), sizeof(Bucket)); ++ zend_mm_safe_error_ex("Possible integer overflow in memory allocation (%u * %zu + %zu)", nSize, sizeof(Bucket), sizeof(Bucket)); + } + + #if defined(ZEND_WIN32) +@@ -251,6 +251,13 @@ ZEND_API HashTable* ZEND_FASTCALL _zend_new_array_0(void) + return ht; + } + ++ZEND_API HashTable* ZEND_FASTCALL zend_new_array_singleton(void) ++{ ++ HashTable *ht = _zend_new_array_0(); ++ ht->nTableSize = 1; ++ return ht; ++} ++ + ZEND_API HashTable* ZEND_FASTCALL _zend_new_array(uint32_t nSize) + { + HashTable *ht = emalloc(sizeof(HashTable)); +@@ -282,7 +289,7 @@ static void ZEND_FASTCALL zend_hash_packed_grow(HashTable *ht) + { + HT_ASSERT_RC1(ht); + if (ht->nTableSize >= HT_MAX_SIZE) { +- zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%u * %zu + %zu)", ht->nTableSize * 2, sizeof(Bucket), sizeof(Bucket)); ++ zend_mm_safe_error_ex("Possible integer overflow in memory allocation (%u * %zu + %zu)", ht->nTableSize * 2, sizeof(Bucket), sizeof(Bucket)); + } + ht->nTableSize += ht->nTableSize; + HT_SET_DATA_ADDR(ht, perealloc2(HT_GET_DATA_ADDR(ht), HT_SIZE_EX(ht->nTableSize, HT_MIN_MASK), HT_USED_SIZE(ht), GC_FLAGS(ht) & IS_ARRAY_PERSISTENT)); +@@ -1164,7 +1171,7 @@ static void ZEND_FASTCALL zend_hash_do_resize(HashTable *ht) + pefree(old_data, GC_FLAGS(ht) & IS_ARRAY_PERSISTENT); + zend_hash_rehash(ht); + } else { +- zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%u * %zu + %zu)", ht->nTableSize * 2, sizeof(Bucket) + sizeof(uint32_t), sizeof(Bucket)); ++ zend_mm_safe_error_ex("Possible integer overflow in memory allocation (%u * %zu + %zu)", ht->nTableSize * 2, sizeof(Bucket) + sizeof(uint32_t), sizeof(Bucket)); + } + } + +diff --git a/Zend/zend_hash.h b/Zend/zend_hash.h +index f1e2d34685d5..b833479eaa10 100644 +--- a/Zend/zend_hash.h ++++ b/Zend/zend_hash.h +@@ -296,6 +296,7 @@ ZEND_API int ZEND_FASTCALL zend_hash_rehash(HashTable *ht); + #endif + + ZEND_API HashTable* ZEND_FASTCALL _zend_new_array_0(void); ++ZEND_API HashTable* ZEND_FASTCALL zend_new_array_singleton(void); + ZEND_API HashTable* ZEND_FASTCALL _zend_new_array(uint32_t size); + ZEND_API HashTable* ZEND_FASTCALL zend_new_pair(zval *val1, zval *val2); + ZEND_API uint32_t zend_array_count(HashTable *ht); +diff --git a/Zend/zend_llist.c b/Zend/zend_llist.c +index 4a2c22e63212..0955e953aa3e 100644 +--- a/Zend/zend_llist.c ++++ b/Zend/zend_llist.c +@@ -112,6 +112,8 @@ ZEND_API void zend_llist_destroy(zend_llist *l) + current = next; + } + ++ l->head = NULL; ++ l->tail = NULL; + l->count = 0; + } + +diff --git a/Zend/zend_multiply.h b/Zend/zend_multiply.h +index a3827d25d128..a9bbda553847 100644 +--- a/Zend/zend_multiply.h ++++ b/Zend/zend_multiply.h +@@ -321,7 +321,7 @@ static zend_always_inline size_t zend_safe_address_guarded(size_t nmemb, size_t + size_t ret = zend_safe_address(nmemb, size, offset, &overflow); + + if (UNEXPECTED(overflow)) { +- zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%zu * %zu + %zu)", nmemb, size, offset); ++ zend_mm_safe_error_ex("Possible integer overflow in memory allocation (%zu * %zu + %zu)", nmemb, size, offset); + return 0; + } + return ret; +@@ -334,7 +334,7 @@ static zend_always_inline size_t zend_safe_addmult(size_t nmemb, size_t size, si + size_t ret = zend_safe_address(nmemb, size, offset, &overflow); + + if (UNEXPECTED(overflow)) { +- zend_error_noreturn(E_ERROR, "Possible integer overflow in %s (%zu * %zu + %zu)", message, nmemb, size, offset); ++ zend_mm_safe_error_ex("Possible integer overflow in %s (%zu * %zu + %zu)", message, nmemb, size, offset); + return 0; + } + return ret; +diff --git a/Zend/zend_strtod.c b/Zend/zend_strtod.c +index 2228e2262cf1..ad8df201af46 100644 +--- a/Zend/zend_strtod.c ++++ b/Zend/zend_strtod.c +@@ -603,7 +603,7 @@ Balloc + rv = (Bigint *)MALLOC(sizeof(Bigint) + (x-1)*sizeof(ULong)); + if (!rv) { + FREE_DTOA_LOCK(0); +- zend_error_noreturn(E_ERROR, "Balloc() failed to allocate memory"); ++ zend_mm_safe_error_ex("Balloc() failed to allocate memory"); + } + #else + len = (sizeof(Bigint) + (x-1)*sizeof(ULong) + sizeof(double) - 1) +@@ -616,7 +616,7 @@ Balloc + rv = (Bigint*)MALLOC(len*sizeof(double)); + if (!rv) { + FREE_DTOA_LOCK(0); +- zend_error_noreturn(E_ERROR, "Balloc() failed to allocate memory"); ++ zend_mm_safe_error_ex("Balloc() failed to allocate memory"); + } + #endif + rv->k = k; +diff --git a/Zend/zend_types.h b/Zend/zend_types.h +index 7b8c079c458d..f7828eb6d373 100644 +--- a/Zend/zend_types.h ++++ b/Zend/zend_types.h +@@ -330,17 +330,21 @@ struct _zend_array { + # define HT_HASH_RESET(ht) do { \ + char *p = (char*)&HT_HASH(ht, (ht)->nTableMask); \ + size_t size = HT_HASH_SIZE((ht)->nTableMask); \ +- __m128i xmm0 = _mm_setzero_si128(); \ +- xmm0 = _mm_cmpeq_epi8(xmm0, xmm0); \ +- ZEND_ASSERT(size >= 64 && ((size & 0x3f) == 0)); \ +- do { \ +- _mm_storeu_si128((__m128i*)p, xmm0); \ +- _mm_storeu_si128((__m128i*)(p+16), xmm0); \ +- _mm_storeu_si128((__m128i*)(p+32), xmm0); \ +- _mm_storeu_si128((__m128i*)(p+48), xmm0); \ +- p += 64; \ +- size -= 64; \ +- } while (size != 0); \ ++ if (UNEXPECTED(size < 64)) { \ ++ memset(p, HT_INVALID_IDX, size); \ ++ } else { \ ++ __m128i xmm0 = _mm_setzero_si128(); \ ++ xmm0 = _mm_cmpeq_epi8(xmm0, xmm0); \ ++ ZEND_ASSERT(size >= 64 && ((size & 0x3f) == 0)); \ ++ do { \ ++ _mm_storeu_si128((__m128i*)p, xmm0); \ ++ _mm_storeu_si128((__m128i*)(p+16), xmm0); \ ++ _mm_storeu_si128((__m128i*)(p+32), xmm0); \ ++ _mm_storeu_si128((__m128i*)(p+48), xmm0); \ ++ p += 64; \ ++ size -= 64; \ ++ } while (size != 0); \ ++ } \ + } while (0) + #else + # define HT_HASH_RESET(ht) \ +diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h +index d362b0164321..3af90d705b52 100644 +--- a/Zend/zend_vm_def.h ++++ b/Zend/zend_vm_def.h +@@ -417,7 +417,7 @@ ZEND_VM_HANDLER(8, ZEND_CONCAT, CONST|TMPVAR|CV, CONST|TMPVAR|CV, SPEC(NO_CONST_ + size_t len = ZSTR_LEN(op1_str); + + if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { +- zend_error_noreturn(E_ERROR, "Integer overflow in memory allocation"); ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); + } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -426,6 +426,9 @@ ZEND_VM_HANDLER(8, ZEND_CONCAT, CONST|TMPVAR|CV, CONST|TMPVAR|CV, SPEC(NO_CONST_ + zend_string_release_ex(op2_str, 0); + } + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -3210,6 +3213,9 @@ ZEND_VM_COLD_CONSTCONST_HANDLER(53, ZEND_FAST_CONCAT, CONST|TMPVAR|CV, CONST|TMP + !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { + size_t len = ZSTR_LEN(op1_str); + ++ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + ZVAL_NEW_STR(EX_VAR(opline->result.var), str); +@@ -3217,6 +3223,9 @@ ZEND_VM_COLD_CONSTCONST_HANDLER(53, ZEND_FAST_CONCAT, CONST|TMPVAR|CV, CONST|TMP + zend_string_release_ex(op2_str, 0); + } + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h +index 2875fd37404a..8701e77ea8d2 100644 +--- a/Zend/zend_vm_execute.h ++++ b/Zend/zend_vm_execute.h +@@ -5631,6 +5631,9 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_ + !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { + size_t len = ZSTR_LEN(op1_str); + ++ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + ZVAL_NEW_STR(EX_VAR(opline->result.var), str); +@@ -5638,6 +5641,9 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_ + zend_string_release_ex(op2_str, 0); + } + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -7491,6 +7497,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_CONST_TMPVAR_HANDL + !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { + size_t len = ZSTR_LEN(op1_str); + ++ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + ZVAL_NEW_STR(EX_VAR(opline->result.var), str); +@@ -7498,6 +7507,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_CONST_TMPVAR_HANDL + zend_string_release_ex(op2_str, 0); + } + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -7900,7 +7912,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CONST_TMPVAR_ + size_t len = ZSTR_LEN(op1_str); + + if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { +- zend_error_noreturn(E_ERROR, "Integer overflow in memory allocation"); ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); + } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -7909,6 +7921,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CONST_TMPVAR_ + zend_string_release_ex(op2_str, 0); + } + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -9952,6 +9967,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_CONST_CV_HANDLER(Z + !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { + size_t len = ZSTR_LEN(op1_str); + ++ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + ZVAL_NEW_STR(EX_VAR(opline->result.var), str); +@@ -9959,6 +9977,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_CONST_CV_HANDLER(Z + zend_string_release_ex(op2_str, 0); + } + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -10361,7 +10382,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CONST_CV_HAND + size_t len = ZSTR_LEN(op1_str); + + if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { +- zend_error_noreturn(E_ERROR, "Integer overflow in memory allocation"); ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); + } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -10370,6 +10391,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CONST_CV_HAND + zend_string_release_ex(op2_str, 0); + } + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -13928,6 +13952,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_TMPVAR_CONST_HANDL + !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { + size_t len = ZSTR_LEN(op1_str); + ++ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + ZVAL_NEW_STR(EX_VAR(opline->result.var), str); +@@ -13935,6 +13962,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_TMPVAR_CONST_HANDL + zend_string_release_ex(op2_str, 0); + } + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -14681,7 +14711,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_TMPVAR_CONST_ + size_t len = ZSTR_LEN(op1_str); + + if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { +- zend_error_noreturn(E_ERROR, "Integer overflow in memory allocation"); ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); + } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -14690,6 +14720,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_TMPVAR_CONST_ + zend_string_release_ex(op2_str, 0); + } + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -15353,7 +15386,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_TMPVAR_TMPVAR_HAND + size_t len = ZSTR_LEN(op1_str); + + if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { +- zend_error_noreturn(E_ERROR, "Integer overflow in memory allocation"); ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); + } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -15362,6 +15395,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_TMPVAR_TMPVAR_HAND + zend_string_release_ex(op2_str, 0); + } + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -16107,6 +16143,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_TMPVAR_TMPVAR + !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { + size_t len = ZSTR_LEN(op1_str); + ++ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + ZVAL_NEW_STR(EX_VAR(opline->result.var), str); +@@ -16114,6 +16153,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_TMPVAR_TMPVAR + zend_string_release_ex(op2_str, 0); + } + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -17040,7 +17082,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_TMPVAR_CV_HANDLER( + size_t len = ZSTR_LEN(op1_str); + + if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { +- zend_error_noreturn(E_ERROR, "Integer overflow in memory allocation"); ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); + } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -17049,6 +17091,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_TMPVAR_CV_HANDLER( + zend_string_release_ex(op2_str, 0); + } + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -17401,6 +17446,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_TMPVAR_CV_HAN + !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { + size_t len = ZSTR_LEN(op1_str); + ++ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + ZVAL_NEW_STR(EX_VAR(opline->result.var), str); +@@ -17408,6 +17456,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_TMPVAR_CV_HAN + zend_string_release_ex(op2_str, 0); + } + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -38348,7 +38399,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_CV_CONST_HANDLER(Z + size_t len = ZSTR_LEN(op1_str); + + if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { +- zend_error_noreturn(E_ERROR, "Integer overflow in memory allocation"); ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); + } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -38357,6 +38408,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_CV_CONST_HANDLER(Z + zend_string_release_ex(op2_str, 0); + } + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -40727,7 +40781,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CV_CONST_HAND + size_t len = ZSTR_LEN(op1_str); + + if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { +- zend_error_noreturn(E_ERROR, "Integer overflow in memory allocation"); ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); + } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -40736,6 +40790,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CV_CONST_HAND + zend_string_release_ex(op2_str, 0); + } + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -41849,6 +41906,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_CV_TMPVAR_HANDLER( + !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { + size_t len = ZSTR_LEN(op1_str); + ++ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + ZVAL_NEW_STR(EX_VAR(opline->result.var), str); +@@ -41856,6 +41916,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_CV_TMPVAR_HANDLER( + zend_string_release_ex(op2_str, 0); + } + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -44132,6 +44195,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CV_TMPVAR_HAN + !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { + size_t len = ZSTR_LEN(op1_str); + ++ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + ZVAL_NEW_STR(EX_VAR(opline->result.var), str); +@@ -44139,6 +44205,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CV_TMPVAR_HAN + zend_string_release_ex(op2_str, 0); + } + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -46857,7 +46926,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_CV_CV_HANDLER(ZEND + size_t len = ZSTR_LEN(op1_str); + + if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { +- zend_error_noreturn(E_ERROR, "Integer overflow in memory allocation"); ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); + } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -46866,6 +46935,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_CV_CV_HANDLER(ZEND + zend_string_release_ex(op2_str, 0); + } + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -49268,6 +49340,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CV_CV_HANDLER + !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { + size_t len = ZSTR_LEN(op1_str); + ++ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + ZVAL_NEW_STR(EX_VAR(opline->result.var), str); +@@ -49275,6 +49350,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CV_CV_HANDLER + zend_string_release_ex(op2_str, 0); + } + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +diff --git a/ext/session/session.c b/ext/session/session.c +index 8fb6dd2cd5d2..89a7400a9ca9 100644 +--- a/ext/session/session.c ++++ b/ext/session/session.c +@@ -3174,7 +3174,7 @@ static int php_session_rfc1867_callback(unsigned int event, void *event_data, vo + if (php_session_rfc1867_orig_callback) { + retval = php_session_rfc1867_orig_callback(event, event_data, extra); + } +- if (!PS(rfc1867_enabled)) { ++ if (!PS(rfc1867_enabled) || true) { + return retval; + } + +diff --git a/main/SAPI.c b/main/SAPI.c +index a5a68f8c680e..1c320f6e3fa3 100644 +--- a/main/SAPI.c ++++ b/main/SAPI.c +@@ -509,18 +509,23 @@ SAPI_API void sapi_deactivate(void) + } + if (SG(request_info).auth_user) { + efree(SG(request_info).auth_user); ++ SG(request_info).auth_user = NULL; + } + if (SG(request_info).auth_password) { + efree(SG(request_info).auth_password); ++ SG(request_info).auth_password = NULL; + } + if (SG(request_info).auth_digest) { + efree(SG(request_info).auth_digest); ++ SG(request_info).auth_digest = NULL; + } + if (SG(request_info).content_type_dup) { + efree(SG(request_info).content_type_dup); ++ SG(request_info).content_type_dup = NULL; + } + if (SG(request_info).current_user) { + efree(SG(request_info).current_user); ++ SG(request_info).current_user = NULL; + } + if (sapi_module.deactivate) { + sapi_module.deactivate(); +diff --git a/main/main.c b/main/main.c +index 0b33b2b56c9a..bb8501f97362 100644 +--- a/main/main.c ++++ b/main/main.c +@@ -836,6 +836,7 @@ PHP_INI_BEGIN() + PHP_INI_ENTRY("disable_functions", "", PHP_INI_SYSTEM, NULL) + PHP_INI_ENTRY("disable_classes", "", PHP_INI_SYSTEM, NULL) + PHP_INI_ENTRY("max_file_uploads", "20", PHP_INI_SYSTEM|PHP_INI_PERDIR, NULL) ++ PHP_INI_ENTRY("max_multipart_body_parts", "-1", PHP_INI_SYSTEM|PHP_INI_PERDIR, NULL) + + STD_PHP_INI_BOOLEAN("allow_url_fopen", "1", PHP_INI_SYSTEM, OnUpdateBool, allow_url_fopen, php_core_globals, core_globals) + STD_PHP_INI_BOOLEAN("allow_url_include", "0", PHP_INI_SYSTEM, OnUpdateBool, allow_url_include, php_core_globals, core_globals) +@@ -1960,6 +1961,8 @@ void php_request_shutdown(void *dummy) + + for (i=0; i +Date: Sun, 18 Oct 2026 20:11:52 +0200 +Subject: [PATCH] Avoid state corruption via bailout + +Minimal mitigation for EOL version. + +Fix GHSA-w8hw-w9fx-j79w (CVE-2026-109618) +Fix GHSA-6wmf-4rv5-p3rp (CVE-2026-109619) + +Co-authored-by: Ilija Tovilo +--- + Zend/zend_API.h | 1 + + Zend/zend_alloc.c | 68 ++++++++++++++++++++--------- + Zend/zend_alloc.h | 2 + + Zend/zend_execute_API.c | 13 ++++++ + Zend/zend_hash.c | 13 ++++-- + Zend/zend_hash.h | 1 + + Zend/zend_llist.c | 2 + + Zend/zend_multiply.h | 4 +- + Zend/zend_strtod.c | 4 +- + Zend/zend_types.h | 26 +++++++----- + Zend/zend_vm_def.h | 11 ++++- + Zend/zend_vm_execute.h | 94 +++++++++++++++++++++++++++++++++++++---- + ext/session/session.c | 2 +- + main/SAPI.c | 5 +++ + main/main.c | 6 +++ + main/php_variables.c | 8 ++-- + main/rfc1867.c | 28 +++++++++--- + 17 files changed, 229 insertions(+), 59 deletions(-) + +diff --git a/Zend/zend_API.h b/Zend/zend_API.h +index 456ef05d802f..0d015bacf349 100644 +--- a/Zend/zend_API.h ++++ b/Zend/zend_API.h +@@ -428,6 +428,7 @@ ZEND_API const char *zend_get_type_by_const(int type); + + #define array_init(arg) ZVAL_ARR((arg), zend_new_array(0)) + #define array_init_size(arg, size) ZVAL_ARR((arg), zend_new_array(size)) ++#define array_init_singleton(arg) ZVAL_ARR((arg), zend_new_array_singleton()) + ZEND_API void object_init(zval *arg); + ZEND_API zend_result object_init_ex(zval *arg, zend_class_entry *ce); + ZEND_API zend_result object_and_properties_init(zval *arg, zend_class_entry *ce, HashTable *properties); +diff --git a/Zend/zend_alloc.c b/Zend/zend_alloc.c +index 6e0ce4b651dc..a21b10f9be43 100644 +--- a/Zend/zend_alloc.c ++++ b/Zend/zend_alloc.c +@@ -57,6 +57,7 @@ + #include "zend_operators.h" + #include "zend_multiply.h" + #include "zend_bitset.h" ++#include "zend_execute.h" + #include + + #ifdef HAVE_UNISTD_H +@@ -363,7 +364,42 @@ static ZEND_COLD ZEND_NORETURN void zend_mm_panic(const char *message) + #if ZEND_DEBUG && defined(HAVE_KILL) && defined(HAVE_GETPID) + kill(getpid(), SIGSEGV); + #endif +- exit(1); ++ _exit(1); ++} ++ ++ZEND_API ZEND_COLD ZEND_NORETURN void zend_mm_safe_error_ex(const char *format, ...) ++{ ++ zend_string *script_filename = NULL; ++ uint32_t script_lineno = 0; ++ ++ if (zend_is_executing()) { ++ script_filename = zend_get_executed_filename_ex(); ++ script_lineno = zend_get_executed_lineno(); ++ } else if (zend_is_compiling()) { ++ script_filename = zend_get_compiled_filename(); ++ script_lineno = zend_get_compiled_lineno(); ++ } ++ ++ va_list args; ++ va_start(args, format); ++ ++ char buf[1024]; ++ vsnprintf(buf, sizeof(buf), format, args); ++ ++ va_end(args); ++ ++ fprintf(stderr, ++ "\nFatal error: %s in %s on line %d\n", ++ buf, ++ script_filename ? ZSTR_VAL(script_filename) : "Unknown", ++ script_lineno); ++ ++ /* See http://support.microsoft.com/kb/190351 */ ++# ifdef ZEND_WIN32 ++ fflush(stderr); ++# endif ++ ++ _exit(1); + } + + static ZEND_COLD ZEND_NORETURN void zend_mm_safe_error(zend_mm_heap *heap, +@@ -375,22 +411,14 @@ static ZEND_COLD ZEND_NORETURN void zend_mm_safe_error(zend_mm_heap *heap, + #endif + size_t size) + { ++ (void) heap; + +- heap->overflow = 1; +- zend_try { +- zend_error_noreturn(E_ERROR, +- format, +- limit, ++ zend_mm_safe_error_ex(format, limit, + #if ZEND_DEBUG +- filename, +- lineno, ++ filename, ++ lineno, + #endif +- size); +- } zend_catch { +- } zend_end_try(); +- heap->overflow = 0; +- zend_bailout(); +- exit(1); ++ size); + } + + #ifdef _WIN32 +@@ -1318,7 +1346,7 @@ static zend_always_inline void *zend_mm_alloc_heap(zend_mm_heap *heap, size_t si + size = MAX(size, 1); + size = ZEND_MM_ALIGNED_SIZE(size) + ZEND_MM_ALIGNED_SIZE(sizeof(zend_mm_debug_info)); + if (UNEXPECTED(size < real_size)) { +- zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%zu + %zu)", ZEND_MM_ALIGNED_SIZE(real_size), ZEND_MM_ALIGNED_SIZE(sizeof(zend_mm_debug_info))); ++ zend_mm_safe_error_ex("Possible integer overflow in memory allocation (%zu + %zu)", ZEND_MM_ALIGNED_SIZE(real_size), ZEND_MM_ALIGNED_SIZE(sizeof(zend_mm_debug_info))); + return NULL; + } + #endif +@@ -1762,7 +1790,7 @@ static void *zend_mm_alloc_huge(zend_mm_heap *heap, size_t size ZEND_FILE_LINE_D + void *ptr; + + if (UNEXPECTED(new_size < size)) { +- zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%zu + %zu)", size, alignment); ++ zend_mm_safe_error_ex("Possible integer overflow in memory allocation (%zu + %zu)", size, alignment); + } + + #if ZEND_MM_LIMIT +@@ -2618,7 +2646,7 @@ ZEND_API char* ZEND_FASTCALL _estrdup(const char *s ZEND_FILE_LINE_DC ZEND_FILE_ + + length = strlen(s); + if (UNEXPECTED(length + 1 == 0)) { +- zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (1 * %zu + 1)", length); ++ zend_mm_safe_error_ex("Possible integer overflow in memory allocation (1 * %zu + 1)", length); + } + p = (char *) _emalloc(length + 1 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC); + memcpy(p, s, length+1); +@@ -2630,7 +2658,7 @@ ZEND_API char* ZEND_FASTCALL _estrndup(const char *s, size_t length ZEND_FILE_LI + char *p; + + if (UNEXPECTED(length + 1 == 0)) { +- zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (1 * %zu + 1)", length); ++ zend_mm_safe_error_ex("Possible integer overflow in memory allocation (1 * %zu + 1)", length); + } + p = (char *) _emalloc(length + 1 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC); + memcpy(p, s, length); +@@ -2644,7 +2672,7 @@ ZEND_API char* ZEND_FASTCALL zend_strndup(const char *s, size_t length) + char *p; + + if (UNEXPECTED(length + 1 == 0)) { +- zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (1 * %zu + 1)", length); ++ zend_mm_safe_error_ex("Possible integer overflow in memory allocation (1 * %zu + 1)", length); + } + p = (char *) malloc(length + 1); + if (UNEXPECTED(p == NULL)) { +@@ -3048,7 +3076,7 @@ ZEND_API zend_mm_heap *zend_mm_startup_ex(const zend_mm_handlers *handlers, void + static ZEND_COLD ZEND_NORETURN void zend_out_of_memory(void) + { + fprintf(stderr, "Out of memory\n"); +- exit(1); ++ _exit(1); + } + + ZEND_API void * __zend_malloc(size_t len) +diff --git a/Zend/zend_alloc.h b/Zend/zend_alloc.h +index de450bbca2fc..f6bc82d2500c 100644 +--- a/Zend/zend_alloc.h ++++ b/Zend/zend_alloc.h +@@ -403,6 +403,8 @@ static void apc_init_heap(void) + size_t zend_mm_globals_size(void); + #endif + ++ZEND_API ZEND_COLD ZEND_NORETURN void zend_mm_safe_error_ex(const char *format, ...); ++ + END_EXTERN_C() + + #endif +diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c +index 18104c2d9953..2f19a17c6bff 100644 +--- a/Zend/zend_execute_API.c ++++ b/Zend/zend_execute_API.c +@@ -334,10 +334,21 @@ void shutdown_executor(void) /* {{{ */ + gc_collect_cycles(); + } + #endif ++ } else { ++ /* may be used by zend_error_zstr_at before init_executor */ ++ ZVAL_UNDEF(&EG(user_error_handler)); ++ ZVAL_UNDEF(&EG(user_exception_handler)); ++ memset(&EG(user_error_handlers_error_reporting), 0, sizeof(EG(user_error_handlers_error_reporting))); ++ memset(&EG(user_error_handlers), 0, sizeof(EG(user_error_handlers))); ++ memset(&EG(user_exception_handlers), 0, sizeof(EG(user_exception_handlers))); + } + + zend_objects_store_free_object_storage(&EG(objects_store), fast_shutdown); + ++ /* may be used by zend_error_zstr_at before init_executor */ ++ EG(error_handling) = EH_NORMAL; ++ EG(exception) = NULL; ++ + zend_weakrefs_shutdown(); + + zend_try { +@@ -354,6 +365,8 @@ void shutdown_executor(void) /* {{{ */ + zend_hash_discard(EG(function_table), EG(persistent_functions_count)); + zend_hash_discard(EG(class_table), EG(persistent_classes_count)); + zend_cleanup_internal_classes(); ++ EG(objects_store).object_buckets = NULL; ++ EG(objects_store).top = 1; + } else { + zend_vm_stack_destroy(); + +diff --git a/Zend/zend_hash.c b/Zend/zend_hash.c +index a3b62160dc6f..a4c318d1239e 100644 +--- a/Zend/zend_hash.c ++++ b/Zend/zend_hash.c +@@ -119,7 +119,7 @@ static zend_always_inline uint32_t zend_hash_check_size(uint32_t nSize) + if (nSize <= HT_MIN_SIZE) { + return HT_MIN_SIZE; + } else if (UNEXPECTED(nSize >= HT_MAX_SIZE)) { +- zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%u * %zu + %zu)", nSize, sizeof(Bucket), sizeof(Bucket)); ++ zend_mm_safe_error_ex("Possible integer overflow in memory allocation (%u * %zu + %zu)", nSize, sizeof(Bucket), sizeof(Bucket)); + } + + #ifdef ZEND_WIN32 +@@ -273,6 +273,13 @@ ZEND_API HashTable* ZEND_FASTCALL _zend_new_array_0(void) + return ht; + } + ++ZEND_API HashTable* ZEND_FASTCALL zend_new_array_singleton(void) ++{ ++ HashTable *ht = _zend_new_array_0(); ++ ht->nTableSize = 1; ++ return ht; ++} ++ + ZEND_API HashTable* ZEND_FASTCALL _zend_new_array(uint32_t nSize) + { + HashTable *ht = emalloc(sizeof(HashTable)); +@@ -304,7 +311,7 @@ static void ZEND_FASTCALL zend_hash_packed_grow(HashTable *ht) + { + HT_ASSERT_RC1(ht); + if (ht->nTableSize >= HT_MAX_SIZE) { +- zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%u * %zu + %zu)", ht->nTableSize * 2, sizeof(Bucket), sizeof(Bucket)); ++ zend_mm_safe_error_ex("Possible integer overflow in memory allocation (%u * %zu + %zu)", ht->nTableSize * 2, sizeof(Bucket), sizeof(Bucket)); + } + ht->nTableSize += ht->nTableSize; + HT_SET_DATA_ADDR(ht, perealloc2(HT_GET_DATA_ADDR(ht), HT_SIZE_EX(ht->nTableSize, HT_MIN_MASK), HT_USED_SIZE(ht), GC_FLAGS(ht) & IS_ARRAY_PERSISTENT)); +@@ -1190,7 +1197,7 @@ static void ZEND_FASTCALL zend_hash_do_resize(HashTable *ht) + pefree(old_data, GC_FLAGS(ht) & IS_ARRAY_PERSISTENT); + zend_hash_rehash(ht); + } else { +- zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%u * %zu + %zu)", ht->nTableSize * 2, sizeof(Bucket) + sizeof(uint32_t), sizeof(Bucket)); ++ zend_mm_safe_error_ex("Possible integer overflow in memory allocation (%u * %zu + %zu)", ht->nTableSize * 2, sizeof(Bucket) + sizeof(uint32_t), sizeof(Bucket)); + } + } + +diff --git a/Zend/zend_hash.h b/Zend/zend_hash.h +index ced21a2ca155..b697acf587be 100644 +--- a/Zend/zend_hash.h ++++ b/Zend/zend_hash.h +@@ -296,6 +296,7 @@ ZEND_API void ZEND_FASTCALL zend_hash_rehash(HashTable *ht); + #endif + + ZEND_API HashTable* ZEND_FASTCALL _zend_new_array_0(void); ++ZEND_API HashTable* ZEND_FASTCALL zend_new_array_singleton(void); + ZEND_API HashTable* ZEND_FASTCALL _zend_new_array(uint32_t size); + ZEND_API HashTable* ZEND_FASTCALL zend_new_pair(zval *val1, zval *val2); + ZEND_API uint32_t zend_array_count(HashTable *ht); +diff --git a/Zend/zend_llist.c b/Zend/zend_llist.c +index 78a3310438f0..8c42b2494ea0 100644 +--- a/Zend/zend_llist.c ++++ b/Zend/zend_llist.c +@@ -112,6 +112,8 @@ ZEND_API void zend_llist_destroy(zend_llist *l) + current = next; + } + ++ l->head = NULL; ++ l->tail = NULL; + l->count = 0; + } + +diff --git a/Zend/zend_multiply.h b/Zend/zend_multiply.h +index c6cd472a237b..bfe1b8e88692 100644 +--- a/Zend/zend_multiply.h ++++ b/Zend/zend_multiply.h +@@ -321,7 +321,7 @@ static zend_always_inline size_t zend_safe_address_guarded(size_t nmemb, size_t + size_t ret = zend_safe_address(nmemb, size, offset, &overflow); + + if (UNEXPECTED(overflow)) { +- zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%zu * %zu + %zu)", nmemb, size, offset); ++ zend_mm_safe_error_ex("Possible integer overflow in memory allocation (%zu * %zu + %zu)", nmemb, size, offset); + return 0; + } + return ret; +@@ -334,7 +334,7 @@ static zend_always_inline size_t zend_safe_addmult(size_t nmemb, size_t size, si + size_t ret = zend_safe_address(nmemb, size, offset, &overflow); + + if (UNEXPECTED(overflow)) { +- zend_error_noreturn(E_ERROR, "Possible integer overflow in %s (%zu * %zu + %zu)", message, nmemb, size, offset); ++ zend_mm_safe_error_ex("Possible integer overflow in %s (%zu * %zu + %zu)", message, nmemb, size, offset); + return 0; + } + return ret; +diff --git a/Zend/zend_strtod.c b/Zend/zend_strtod.c +index e88fbd001fef..fd6b23c9cbfc 100644 +--- a/Zend/zend_strtod.c ++++ b/Zend/zend_strtod.c +@@ -603,7 +603,7 @@ Balloc + rv = (Bigint *)MALLOC(sizeof(Bigint) + (x-1)*sizeof(ULong)); + if (!rv) { + FREE_DTOA_LOCK(0); +- zend_error_noreturn(E_ERROR, "Balloc() failed to allocate memory"); ++ zend_mm_safe_error_ex("Balloc() failed to allocate memory"); + } + #else + len = (sizeof(Bigint) + (x-1)*sizeof(ULong) + sizeof(double) - 1) +@@ -616,7 +616,7 @@ Balloc + rv = (Bigint*)MALLOC(len*sizeof(double)); + if (!rv) { + FREE_DTOA_LOCK(0); +- zend_error_noreturn(E_ERROR, "Balloc() failed to allocate memory"); ++ zend_mm_safe_error_ex("Balloc() failed to allocate memory"); + } + #endif + rv->k = k; +diff --git a/Zend/zend_types.h b/Zend/zend_types.h +index 82cf20f1b5d7..1a10ba718c9f 100644 +--- a/Zend/zend_types.h ++++ b/Zend/zend_types.h +@@ -439,17 +439,21 @@ struct _zend_array { + # define HT_HASH_RESET(ht) do { \ + char *p = (char*)&HT_HASH(ht, (ht)->nTableMask); \ + size_t size = HT_HASH_SIZE((ht)->nTableMask); \ +- __m128i xmm0 = _mm_setzero_si128(); \ +- xmm0 = _mm_cmpeq_epi8(xmm0, xmm0); \ +- ZEND_ASSERT(size >= 64 && ((size & 0x3f) == 0)); \ +- do { \ +- _mm_storeu_si128((__m128i*)p, xmm0); \ +- _mm_storeu_si128((__m128i*)(p+16), xmm0); \ +- _mm_storeu_si128((__m128i*)(p+32), xmm0); \ +- _mm_storeu_si128((__m128i*)(p+48), xmm0); \ +- p += 64; \ +- size -= 64; \ +- } while (size != 0); \ ++ if (UNEXPECTED(size < 64)) { \ ++ memset(p, HT_INVALID_IDX, size); \ ++ } else { \ ++ __m128i xmm0 = _mm_setzero_si128(); \ ++ xmm0 = _mm_cmpeq_epi8(xmm0, xmm0); \ ++ ZEND_ASSERT(size >= 64 && ((size & 0x3f) == 0)); \ ++ do { \ ++ _mm_storeu_si128((__m128i*)p, xmm0); \ ++ _mm_storeu_si128((__m128i*)(p+16), xmm0); \ ++ _mm_storeu_si128((__m128i*)(p+32), xmm0); \ ++ _mm_storeu_si128((__m128i*)(p+48), xmm0); \ ++ p += 64; \ ++ size -= 64; \ ++ } while (size != 0); \ ++ } \ + } while (0) + #else + # define HT_HASH_RESET(ht) \ +diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h +index bcb9be8dab48..406350ef260b 100644 +--- a/Zend/zend_vm_def.h ++++ b/Zend/zend_vm_def.h +@@ -408,7 +408,7 @@ ZEND_VM_HANDLER(8, ZEND_CONCAT, CONST|TMPVAR|CV, CONST|TMPVAR|CV, SPEC(NO_CONST_ + size_t len = ZSTR_LEN(op1_str); + + if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { +- zend_error_noreturn(E_ERROR, "Integer overflow in memory allocation"); ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); + } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -417,6 +417,9 @@ ZEND_VM_HANDLER(8, ZEND_CONCAT, CONST|TMPVAR|CV, CONST|TMPVAR|CV, SPEC(NO_CONST_ + zend_string_release_ex(op2_str, 0); + } + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -3157,6 +3160,9 @@ ZEND_VM_COLD_CONSTCONST_HANDLER(53, ZEND_FAST_CONCAT, CONST|TMPVAR|CV, CONST|TMP + !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { + size_t len = ZSTR_LEN(op1_str); + ++ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + ZVAL_NEW_STR(EX_VAR(opline->result.var), str); +@@ -3164,6 +3170,9 @@ ZEND_VM_COLD_CONSTCONST_HANDLER(53, ZEND_FAST_CONCAT, CONST|TMPVAR|CV, CONST|TMP + zend_string_release_ex(op2_str, 0); + } + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h +index 049d0f2126bc..eeca7ebb75a6 100644 +--- a/Zend/zend_vm_execute.h ++++ b/Zend/zend_vm_execute.h +@@ -6348,6 +6348,9 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_ + !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { + size_t len = ZSTR_LEN(op1_str); + ++ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + ZVAL_NEW_STR(EX_VAR(opline->result.var), str); +@@ -6355,6 +6358,9 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_ + zend_string_release_ex(op2_str, 0); + } + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -8225,7 +8231,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_CONST_TMPVAR_HANDL + size_t len = ZSTR_LEN(op1_str); + + if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { +- zend_error_noreturn(E_ERROR, "Integer overflow in memory allocation"); ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); + } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -8234,6 +8240,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_CONST_TMPVAR_HANDL + zend_string_release_ex(op2_str, 0); + } + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -8641,6 +8650,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CONST_TMPVAR_ + !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { + size_t len = ZSTR_LEN(op1_str); + ++ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + ZVAL_NEW_STR(EX_VAR(opline->result.var), str); +@@ -8648,6 +8660,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CONST_TMPVAR_ + zend_string_release_ex(op2_str, 0); + } + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -10613,7 +10628,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_CONST_CV_HANDLER(Z + size_t len = ZSTR_LEN(op1_str); + + if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { +- zend_error_noreturn(E_ERROR, "Integer overflow in memory allocation"); ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); + } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -10622,6 +10637,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_CONST_CV_HANDLER(Z + zend_string_release_ex(op2_str, 0); + } + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -11029,6 +11047,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CONST_CV_HAND + !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { + size_t len = ZSTR_LEN(op1_str); + ++ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + ZVAL_NEW_STR(EX_VAR(opline->result.var), str); +@@ -11036,6 +11057,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CONST_CV_HAND + zend_string_release_ex(op2_str, 0); + } + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -14644,7 +14668,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_TMPVAR_CONST_HANDL + size_t len = ZSTR_LEN(op1_str); + + if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { +- zend_error_noreturn(E_ERROR, "Integer overflow in memory allocation"); ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); + } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -14653,6 +14677,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_TMPVAR_CONST_HANDL + zend_string_release_ex(op2_str, 0); + } + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -15374,6 +15401,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_TMPVAR_CONST_ + !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { + size_t len = ZSTR_LEN(op1_str); + ++ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + ZVAL_NEW_STR(EX_VAR(opline->result.var), str); +@@ -15381,6 +15411,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_TMPVAR_CONST_ + zend_string_release_ex(op2_str, 0); + } + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -16067,7 +16100,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_TMPVAR_TMPVAR_HAND + size_t len = ZSTR_LEN(op1_str); + + if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { +- zend_error_noreturn(E_ERROR, "Integer overflow in memory allocation"); ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); + } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -16076,6 +16109,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_TMPVAR_TMPVAR_HAND + zend_string_release_ex(op2_str, 0); + } + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -16797,6 +16833,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_TMPVAR_TMPVAR + !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { + size_t len = ZSTR_LEN(op1_str); + ++ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + ZVAL_NEW_STR(EX_VAR(opline->result.var), str); +@@ -16804,6 +16843,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_TMPVAR_TMPVAR + zend_string_release_ex(op2_str, 0); + } + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -17744,7 +17786,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_TMPVAR_CV_HANDLER( + size_t len = ZSTR_LEN(op1_str); + + if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { +- zend_error_noreturn(E_ERROR, "Integer overflow in memory allocation"); ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); + } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -17753,6 +17795,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_TMPVAR_CV_HANDLER( + zend_string_release_ex(op2_str, 0); + } + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -18112,6 +18157,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_TMPVAR_CV_HAN + !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { + size_t len = ZSTR_LEN(op1_str); + ++ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + ZVAL_NEW_STR(EX_VAR(opline->result.var), str); +@@ -18119,6 +18167,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_TMPVAR_CV_HAN + zend_string_release_ex(op2_str, 0); + } + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -39226,7 +39277,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_CV_CONST_HANDLER(Z + size_t len = ZSTR_LEN(op1_str); + + if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { +- zend_error_noreturn(E_ERROR, "Integer overflow in memory allocation"); ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); + } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -39235,6 +39286,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_CV_CONST_HANDLER(Z + zend_string_release_ex(op2_str, 0); + } + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -41677,6 +41731,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CV_CONST_HAND + !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { + size_t len = ZSTR_LEN(op1_str); + ++ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + ZVAL_NEW_STR(EX_VAR(opline->result.var), str); +@@ -41684,6 +41741,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CV_CONST_HAND + zend_string_release_ex(op2_str, 0); + } + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -42951,7 +43011,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_CV_TMPVAR_HANDLER( + size_t len = ZSTR_LEN(op1_str); + + if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { +- zend_error_noreturn(E_ERROR, "Integer overflow in memory allocation"); ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); + } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -42960,6 +43020,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_CV_TMPVAR_HANDLER( + zend_string_release_ex(op2_str, 0); + } + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -45331,6 +45394,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CV_TMPVAR_HAN + !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { + size_t len = ZSTR_LEN(op1_str); + ++ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + ZVAL_NEW_STR(EX_VAR(opline->result.var), str); +@@ -45338,6 +45404,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CV_TMPVAR_HAN + zend_string_release_ex(op2_str, 0); + } + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -48150,7 +48219,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_CV_CV_HANDLER(ZEND + size_t len = ZSTR_LEN(op1_str); + + if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { +- zend_error_noreturn(E_ERROR, "Integer overflow in memory allocation"); ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); + } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -48159,6 +48228,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_CV_CV_HANDLER(ZEND + zend_string_release_ex(op2_str, 0); + } + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -50629,6 +50701,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CV_CV_HANDLER + !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { + size_t len = ZSTR_LEN(op1_str); + ++ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + ZVAL_NEW_STR(EX_VAR(opline->result.var), str); +@@ -50636,6 +50711,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CV_CV_HANDLER + zend_string_release_ex(op2_str, 0); + } + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +diff --git a/ext/session/session.c b/ext/session/session.c +index 3c875296c3a1..0c45b1bb41db 100644 +--- a/ext/session/session.c ++++ b/ext/session/session.c +@@ -3017,7 +3017,7 @@ static int php_session_rfc1867_callback(unsigned int event, void *event_data, vo + if (php_session_rfc1867_orig_callback) { + retval = php_session_rfc1867_orig_callback(event, event_data, extra); + } +- if (!PS(rfc1867_enabled)) { ++ if (!PS(rfc1867_enabled) || true) { + return retval; + } + +diff --git a/main/SAPI.c b/main/SAPI.c +index eea417cedcc3..85d964d21bdb 100644 +--- a/main/SAPI.c ++++ b/main/SAPI.c +@@ -503,18 +503,23 @@ SAPI_API void sapi_deactivate_module(void) + } + if (SG(request_info).auth_user) { + efree(SG(request_info).auth_user); ++ SG(request_info).auth_user = NULL; + } + if (SG(request_info).auth_password) { + efree(SG(request_info).auth_password); ++ SG(request_info).auth_password = NULL; + } + if (SG(request_info).auth_digest) { + efree(SG(request_info).auth_digest); ++ SG(request_info).auth_digest = NULL; + } + if (SG(request_info).content_type_dup) { + efree(SG(request_info).content_type_dup); ++ SG(request_info).content_type_dup = NULL; + } + if (SG(request_info).current_user) { + efree(SG(request_info).current_user); ++ SG(request_info).current_user = NULL; + } + if (sapi_module.deactivate) { + sapi_module.deactivate(); +diff --git a/main/main.c b/main/main.c +index c58ea58bf5ac..48feda4bc7e3 100644 +--- a/main/main.c ++++ b/main/main.c +@@ -1847,6 +1847,8 @@ void php_request_shutdown(void *dummy) + + for (i=0; i +Date: Sun, 18 Oct 2026 20:12:35 +0200 +Subject: [PATCH] Avoid state corruption via bailout + +Minimal mitigation for EOL version. + +Fix GHSA-w8hw-w9fx-j79w (CVE-2026-109618) +Fix GHSA-6wmf-4rv5-p3rp (CVE-2026-109619) + +Co-authored-by: Ilija Tovilo +--- + Zend/zend_API.h | 1 + + Zend/zend_alloc.c | 68 +++++++++----- + Zend/zend_alloc.h | 2 + + Zend/zend_execute_API.c | 15 ++++ + Zend/zend_hash.c | 13 ++- + Zend/zend_hash.h | 1 + + Zend/zend_multiply.h | 4 +- + Zend/zend_strtod.c | 4 +- + Zend/zend_types.h | 26 +++--- + Zend/zend_vm_def.h | 11 ++- + Zend/zend_vm_execute.h | 94 ++++++++++++++++++-- + ext/opcache/ZendAccelerator.c | 5 ++ + ext/opcache/ZendAccelerator.h | 11 ++- + ext/opcache/zend_file_cache.c | 8 ++ + ext/opcache/zend_persist.c | 67 ++++++++++++-- + ext/session/session.c | 2 +- + ext/zend_test/tests/observer_bug81430_2.phpt | 2 - + ext/zend_test/tests/observer_bug81435.phpt | 1 - + ext/zend_test/tests/observer_error_01.phpt | 2 - + main/SAPI.c | 5 ++ + main/main.c | 6 ++ + main/php_variables.c | 8 +- + main/rfc1867.c | 28 ++++-- + 23 files changed, 311 insertions(+), 73 deletions(-) + +diff --git a/Zend/zend_API.h b/Zend/zend_API.h +index 9ed1a3fbabd2..a32b83c0533d 100644 +--- a/Zend/zend_API.h ++++ b/Zend/zend_API.h +@@ -490,6 +490,7 @@ ZEND_API const char *zend_get_type_by_const(int type); + + #define array_init(arg) ZVAL_ARR((arg), zend_new_array(0)) + #define array_init_size(arg, size) ZVAL_ARR((arg), zend_new_array(size)) ++#define array_init_singleton(arg) ZVAL_ARR((arg), zend_new_array_singleton()) + ZEND_API void object_init(zval *arg); + ZEND_API zend_result object_init_ex(zval *arg, zend_class_entry *ce); + ZEND_API zend_result object_and_properties_init(zval *arg, zend_class_entry *ce, HashTable *properties); +diff --git a/Zend/zend_alloc.c b/Zend/zend_alloc.c +index 61792b37c9c5..7f43a7f6df07 100644 +--- a/Zend/zend_alloc.c ++++ b/Zend/zend_alloc.c +@@ -57,6 +57,7 @@ + #include "zend_operators.h" + #include "zend_multiply.h" + #include "zend_bitset.h" ++#include "zend_execute.h" + #include + + #ifdef HAVE_UNISTD_H +@@ -364,7 +365,42 @@ static ZEND_COLD ZEND_NORETURN void zend_mm_panic(const char *message) + #if ZEND_DEBUG && defined(HAVE_KILL) && defined(HAVE_GETPID) + kill(getpid(), SIGSEGV); + #endif +- exit(1); ++ _exit(1); ++} ++ ++ZEND_API ZEND_COLD ZEND_NORETURN void zend_mm_safe_error_ex(const char *format, ...) ++{ ++ zend_string *script_filename = NULL; ++ uint32_t script_lineno = 0; ++ ++ if (zend_is_executing()) { ++ script_filename = zend_get_executed_filename_ex(); ++ script_lineno = zend_get_executed_lineno(); ++ } else if (zend_is_compiling()) { ++ script_filename = zend_get_compiled_filename(); ++ script_lineno = zend_get_compiled_lineno(); ++ } ++ ++ va_list args; ++ va_start(args, format); ++ ++ char buf[1024]; ++ vsnprintf(buf, sizeof(buf), format, args); ++ ++ va_end(args); ++ ++ fprintf(stderr, ++ "\nFatal error: %s in %s on line %d\n", ++ buf, ++ script_filename ? ZSTR_VAL(script_filename) : "Unknown", ++ script_lineno); ++ ++ /* See http://support.microsoft.com/kb/190351 */ ++# ifdef ZEND_WIN32 ++ fflush(stderr); ++# endif ++ ++ _exit(1); + } + + static ZEND_COLD ZEND_NORETURN void zend_mm_safe_error(zend_mm_heap *heap, +@@ -376,22 +412,14 @@ static ZEND_COLD ZEND_NORETURN void zend_mm_safe_error(zend_mm_heap *heap, + #endif + size_t size) + { ++ (void) heap; + +- heap->overflow = 1; +- zend_try { +- zend_error_noreturn(E_ERROR, +- format, +- limit, ++ zend_mm_safe_error_ex(format, limit, + #if ZEND_DEBUG +- filename, +- lineno, ++ filename, ++ lineno, + #endif +- size); +- } zend_catch { +- } zend_end_try(); +- heap->overflow = 0; +- zend_bailout(); +- exit(1); ++ size); + } + + #ifdef _WIN32 +@@ -1356,7 +1384,7 @@ static zend_always_inline void *zend_mm_alloc_heap(zend_mm_heap *heap, size_t si + size = MAX(size, 1); + size = ZEND_MM_ALIGNED_SIZE(size) + ZEND_MM_ALIGNED_SIZE(sizeof(zend_mm_debug_info)); + if (UNEXPECTED(size < real_size)) { +- zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%zu + %zu)", ZEND_MM_ALIGNED_SIZE(real_size), ZEND_MM_ALIGNED_SIZE(sizeof(zend_mm_debug_info))); ++ zend_mm_safe_error_ex("Possible integer overflow in memory allocation (%zu + %zu)", ZEND_MM_ALIGNED_SIZE(real_size), ZEND_MM_ALIGNED_SIZE(sizeof(zend_mm_debug_info))); + return NULL; + } + #endif +@@ -1800,7 +1828,7 @@ static void *zend_mm_alloc_huge(zend_mm_heap *heap, size_t size ZEND_FILE_LINE_D + void *ptr; + + if (UNEXPECTED(new_size < size)) { +- zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%zu + %zu)", size, alignment); ++ zend_mm_safe_error_ex("Possible integer overflow in memory allocation (%zu + %zu)", size, alignment); + } + + #if ZEND_MM_LIMIT +@@ -2660,7 +2688,7 @@ ZEND_API char* ZEND_FASTCALL _estrdup(const char *s ZEND_FILE_LINE_DC ZEND_FILE_ + + length = strlen(s); + if (UNEXPECTED(length + 1 == 0)) { +- zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (1 * %zu + 1)", length); ++ zend_mm_safe_error_ex("Possible integer overflow in memory allocation (1 * %zu + 1)", length); + } + p = (char *) _emalloc(length + 1 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC); + memcpy(p, s, length+1); +@@ -2672,7 +2700,7 @@ ZEND_API char* ZEND_FASTCALL _estrndup(const char *s, size_t length ZEND_FILE_LI + char *p; + + if (UNEXPECTED(length + 1 == 0)) { +- zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (1 * %zu + 1)", length); ++ zend_mm_safe_error_ex("Possible integer overflow in memory allocation (1 * %zu + 1)", length); + } + p = (char *) _emalloc(length + 1 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC); + memcpy(p, s, length); +@@ -2686,7 +2714,7 @@ ZEND_API char* ZEND_FASTCALL zend_strndup(const char *s, size_t length) + char *p; + + if (UNEXPECTED(length + 1 == 0)) { +- zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (1 * %zu + 1)", length); ++ zend_mm_safe_error_ex("Possible integer overflow in memory allocation (1 * %zu + 1)", length); + } + p = (char *) malloc(length + 1); + if (UNEXPECTED(p == NULL)) { +@@ -3084,7 +3112,7 @@ ZEND_API zend_mm_heap *zend_mm_startup_ex(const zend_mm_handlers *handlers, void + static ZEND_COLD ZEND_NORETURN void zend_out_of_memory(void) + { + fprintf(stderr, "Out of memory\n"); +- exit(1); ++ _exit(1); + } + + ZEND_API void * __zend_malloc(size_t len) +diff --git a/Zend/zend_alloc.h b/Zend/zend_alloc.h +index 9603af8a27d3..72becadc7746 100644 +--- a/Zend/zend_alloc.h ++++ b/Zend/zend_alloc.h +@@ -403,6 +403,8 @@ static void apc_init_heap(void) + size_t zend_mm_globals_size(void); + #endif + ++ZEND_API ZEND_COLD ZEND_NORETURN void zend_mm_safe_error_ex(const char *format, ...); ++ + END_EXTERN_C() + + #endif +diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c +index 1e31934f1581..82cea225a8ed 100644 +--- a/Zend/zend_execute_API.c ++++ b/Zend/zend_execute_API.c +@@ -385,6 +385,12 @@ ZEND_API void zend_shutdown_executor_values(bool fast_shutdown) + #endif + } else { + zend_hash_discard(EG(zend_constants), EG(persistent_constants_count)); ++ /* may be used by zend_error_zstr_at before init_executor */ ++ ZVAL_UNDEF(&EG(user_error_handler)); ++ ZVAL_UNDEF(&EG(user_exception_handler)); ++ memset(&EG(user_error_handlers_error_reporting), 0, sizeof(EG(user_error_handlers_error_reporting))); ++ memset(&EG(user_error_handlers), 0, sizeof(EG(user_error_handlers))); ++ memset(&EG(user_exception_handlers), 0, sizeof(EG(user_exception_handlers))); + } + + zend_objects_store_free_object_storage(&EG(objects_store), fast_shutdown); +@@ -406,6 +412,13 @@ void shutdown_executor(void) /* {{{ */ + + zend_shutdown_executor_values(fast_shutdown); + ++ /* may be used by zend_error_zstr_at before init_executor */ ++ EG(record_errors) = false; ++ EG(num_errors) = 0; ++ EG(errors) = NULL; ++ EG(error_handling) = EH_NORMAL; ++ EG(exception) = NULL; ++ + zend_weakrefs_shutdown(); + zend_max_execution_timer_shutdown(); + zend_fiber_shutdown(); +@@ -422,6 +435,8 @@ void shutdown_executor(void) /* {{{ */ + */ + zend_hash_discard(EG(function_table), EG(persistent_functions_count)); + zend_hash_discard(EG(class_table), EG(persistent_classes_count)); ++ EG(objects_store).object_buckets = NULL; ++ EG(objects_store).top = 1; + } else { + zend_vm_stack_destroy(); + +diff --git a/Zend/zend_hash.c b/Zend/zend_hash.c +index b96a95110117..65f31c2b9a21 100644 +--- a/Zend/zend_hash.c ++++ b/Zend/zend_hash.c +@@ -119,7 +119,7 @@ static zend_always_inline uint32_t zend_hash_check_size(uint32_t nSize) + if (nSize <= HT_MIN_SIZE) { + return HT_MIN_SIZE; + } else if (UNEXPECTED(nSize >= HT_MAX_SIZE)) { +- zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%u * %zu + %zu)", nSize, sizeof(Bucket), sizeof(Bucket)); ++ zend_mm_safe_error_ex("Possible integer overflow in memory allocation (%u * %zu + %zu)", nSize, sizeof(Bucket), sizeof(Bucket)); + } + + #ifdef ZEND_WIN32 +@@ -276,6 +276,13 @@ ZEND_API HashTable* ZEND_FASTCALL _zend_new_array_0(void) + return ht; + } + ++ZEND_API HashTable* ZEND_FASTCALL zend_new_array_singleton(void) ++{ ++ HashTable *ht = _zend_new_array_0(); ++ ht->nTableSize = 1; ++ return ht; ++} ++ + ZEND_API HashTable* ZEND_FASTCALL _zend_new_array(uint32_t nSize) + { + HashTable *ht = emalloc(sizeof(HashTable)); +@@ -307,7 +314,7 @@ ZEND_API void ZEND_FASTCALL zend_hash_packed_grow(HashTable *ht) + { + HT_ASSERT_RC1(ht); + if (ht->nTableSize >= HT_MAX_SIZE) { +- zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%u * %zu + %zu)", ht->nTableSize * 2, sizeof(Bucket), sizeof(Bucket)); ++ zend_mm_safe_error_ex("Possible integer overflow in memory allocation (%u * %zu + %zu)", ht->nTableSize * 2, sizeof(Bucket), sizeof(Bucket)); + } + uint32_t newTableSize = ht->nTableSize * 2; + HT_SET_DATA_ADDR(ht, perealloc2(HT_GET_DATA_ADDR(ht), HT_SIZE_EX(newTableSize, HT_MIN_MASK), HT_USED_SIZE(ht), GC_FLAGS(ht) & IS_ARRAY_PERSISTENT)); +@@ -1233,7 +1240,7 @@ static void ZEND_FASTCALL zend_hash_do_resize(HashTable *ht) + pefree(old_data, GC_FLAGS(ht) & IS_ARRAY_PERSISTENT); + zend_hash_rehash(ht); + } else { +- zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%u * %zu + %zu)", ht->nTableSize * 2, sizeof(Bucket) + sizeof(uint32_t), sizeof(Bucket)); ++ zend_mm_safe_error_ex("Possible integer overflow in memory allocation (%u * %zu + %zu)", ht->nTableSize * 2, sizeof(Bucket) + sizeof(uint32_t), sizeof(Bucket)); + } + } + +diff --git a/Zend/zend_hash.h b/Zend/zend_hash.h +index 092682d67713..09a7994d91d5 100644 +--- a/Zend/zend_hash.h ++++ b/Zend/zend_hash.h +@@ -314,6 +314,7 @@ ZEND_API void ZEND_FASTCALL zend_hash_rehash(HashTable *ht); + #endif + + ZEND_API HashTable* ZEND_FASTCALL _zend_new_array_0(void); ++ZEND_API HashTable* ZEND_FASTCALL zend_new_array_singleton(void); + ZEND_API HashTable* ZEND_FASTCALL _zend_new_array(uint32_t size); + ZEND_API HashTable* ZEND_FASTCALL zend_new_pair(zval *val1, zval *val2); + ZEND_API uint32_t zend_array_count(HashTable *ht); +diff --git a/Zend/zend_multiply.h b/Zend/zend_multiply.h +index c6cd472a237b..bfe1b8e88692 100644 +--- a/Zend/zend_multiply.h ++++ b/Zend/zend_multiply.h +@@ -321,7 +321,7 @@ static zend_always_inline size_t zend_safe_address_guarded(size_t nmemb, size_t + size_t ret = zend_safe_address(nmemb, size, offset, &overflow); + + if (UNEXPECTED(overflow)) { +- zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%zu * %zu + %zu)", nmemb, size, offset); ++ zend_mm_safe_error_ex("Possible integer overflow in memory allocation (%zu * %zu + %zu)", nmemb, size, offset); + return 0; + } + return ret; +@@ -334,7 +334,7 @@ static zend_always_inline size_t zend_safe_addmult(size_t nmemb, size_t size, si + size_t ret = zend_safe_address(nmemb, size, offset, &overflow); + + if (UNEXPECTED(overflow)) { +- zend_error_noreturn(E_ERROR, "Possible integer overflow in %s (%zu * %zu + %zu)", message, nmemb, size, offset); ++ zend_mm_safe_error_ex("Possible integer overflow in %s (%zu * %zu + %zu)", message, nmemb, size, offset); + return 0; + } + return ret; +diff --git a/Zend/zend_strtod.c b/Zend/zend_strtod.c +index 3e7f90378ef5..7f72c82f610e 100644 +--- a/Zend/zend_strtod.c ++++ b/Zend/zend_strtod.c +@@ -593,7 +593,7 @@ Balloc + rv = (Bigint *)MALLOC(sizeof(Bigint) + (x-1)*sizeof(ULong)); + if (!rv) { + FREE_DTOA_LOCK(0); +- zend_error_noreturn(E_ERROR, "Balloc() failed to allocate memory"); ++ zend_mm_safe_error_ex("Balloc() failed to allocate memory"); + } + #else + len = (sizeof(Bigint) + (x-1)*sizeof(ULong) + sizeof(double) - 1) +@@ -606,7 +606,7 @@ Balloc + rv = (Bigint*)MALLOC(len*sizeof(double)); + if (!rv) { + FREE_DTOA_LOCK(0); +- zend_error_noreturn(E_ERROR, "Balloc() failed to allocate memory"); ++ zend_mm_safe_error_ex("Balloc() failed to allocate memory"); + } + #endif + rv->k = k; +diff --git a/Zend/zend_types.h b/Zend/zend_types.h +index 5bc47dd31934..ab28b0fa163b 100644 +--- a/Zend/zend_types.h ++++ b/Zend/zend_types.h +@@ -448,17 +448,21 @@ struct _zend_array { + # define HT_HASH_RESET(ht) do { \ + char *p = (char*)&HT_HASH(ht, (ht)->nTableMask); \ + size_t size = HT_HASH_SIZE((ht)->nTableMask); \ +- __m128i xmm0 = _mm_setzero_si128(); \ +- xmm0 = _mm_cmpeq_epi8(xmm0, xmm0); \ +- ZEND_ASSERT(size >= 64 && ((size & 0x3f) == 0)); \ +- do { \ +- _mm_storeu_si128((__m128i*)p, xmm0); \ +- _mm_storeu_si128((__m128i*)(p+16), xmm0); \ +- _mm_storeu_si128((__m128i*)(p+32), xmm0); \ +- _mm_storeu_si128((__m128i*)(p+48), xmm0); \ +- p += 64; \ +- size -= 64; \ +- } while (size != 0); \ ++ if (UNEXPECTED(size < 64)) { \ ++ memset(p, HT_INVALID_IDX, size); \ ++ } else { \ ++ __m128i xmm0 = _mm_setzero_si128(); \ ++ xmm0 = _mm_cmpeq_epi8(xmm0, xmm0); \ ++ ZEND_ASSERT(size >= 64 && ((size & 0x3f) == 0)); \ ++ do { \ ++ _mm_storeu_si128((__m128i*)p, xmm0); \ ++ _mm_storeu_si128((__m128i*)(p+16), xmm0); \ ++ _mm_storeu_si128((__m128i*)(p+32), xmm0); \ ++ _mm_storeu_si128((__m128i*)(p+48), xmm0); \ ++ p += 64; \ ++ size -= 64; \ ++ } while (size != 0); \ ++ } \ + } while (0) + #else + # define HT_HASH_RESET(ht) \ +diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h +index a6f86a9eab6f..ad893ebfb5c6 100644 +--- a/Zend/zend_vm_def.h ++++ b/Zend/zend_vm_def.h +@@ -408,7 +408,7 @@ ZEND_VM_HANDLER(8, ZEND_CONCAT, CONST|TMPVAR|CV, CONST|TMPVAR|CV, SPEC(NO_CONST_ + size_t len = ZSTR_LEN(op1_str); + + if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { +- zend_error_noreturn(E_ERROR, "Integer overflow in memory allocation"); ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); + } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -417,6 +417,9 @@ ZEND_VM_HANDLER(8, ZEND_CONCAT, CONST|TMPVAR|CV, CONST|TMPVAR|CV, SPEC(NO_CONST_ + zend_string_release_ex(op2_str, 0); + } + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -3183,6 +3186,9 @@ ZEND_VM_COLD_CONSTCONST_HANDLER(53, ZEND_FAST_CONCAT, CONST|TMPVAR|CV, CONST|TMP + !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { + size_t len = ZSTR_LEN(op1_str); + ++ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + ZVAL_NEW_STR(EX_VAR(opline->result.var), str); +@@ -3190,6 +3196,9 @@ ZEND_VM_COLD_CONSTCONST_HANDLER(53, ZEND_FAST_CONCAT, CONST|TMPVAR|CV, CONST|TMP + zend_string_release_ex(op2_str, 0); + } + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h +index 5ee1c2c94daf..dc78ba4a08d0 100644 +--- a/Zend/zend_vm_execute.h ++++ b/Zend/zend_vm_execute.h +@@ -6549,6 +6549,9 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_ + !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { + size_t len = ZSTR_LEN(op1_str); + ++ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + ZVAL_NEW_STR(EX_VAR(opline->result.var), str); +@@ -6556,6 +6559,9 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_ + zend_string_release_ex(op2_str, 0); + } + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -8456,7 +8462,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_CONST_TMPVAR_HANDL + size_t len = ZSTR_LEN(op1_str); + + if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { +- zend_error_noreturn(E_ERROR, "Integer overflow in memory allocation"); ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); + } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -8465,6 +8471,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_CONST_TMPVAR_HANDL + zend_string_release_ex(op2_str, 0); + } + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -8872,6 +8881,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CONST_TMPVAR_ + !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { + size_t len = ZSTR_LEN(op1_str); + ++ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + ZVAL_NEW_STR(EX_VAR(opline->result.var), str); +@@ -8879,6 +8891,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CONST_TMPVAR_ + zend_string_release_ex(op2_str, 0); + } + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -10821,7 +10836,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_CONST_CV_HANDLER(Z + size_t len = ZSTR_LEN(op1_str); + + if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { +- zend_error_noreturn(E_ERROR, "Integer overflow in memory allocation"); ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); + } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -10830,6 +10845,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_CONST_CV_HANDLER(Z + zend_string_release_ex(op2_str, 0); + } + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -11237,6 +11255,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CONST_CV_HAND + !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { + size_t len = ZSTR_LEN(op1_str); + ++ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + ZVAL_NEW_STR(EX_VAR(opline->result.var), str); +@@ -11244,6 +11265,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CONST_CV_HAND + zend_string_release_ex(op2_str, 0); + } + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -14866,7 +14890,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_TMPVAR_CONST_HANDL + size_t len = ZSTR_LEN(op1_str); + + if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { +- zend_error_noreturn(E_ERROR, "Integer overflow in memory allocation"); ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); + } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -14875,6 +14899,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_TMPVAR_CONST_HANDL + zend_string_release_ex(op2_str, 0); + } + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -15596,6 +15623,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_TMPVAR_CONST_ + !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { + size_t len = ZSTR_LEN(op1_str); + ++ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + ZVAL_NEW_STR(EX_VAR(opline->result.var), str); +@@ -15603,6 +15633,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_TMPVAR_CONST_ + zend_string_release_ex(op2_str, 0); + } + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -16295,7 +16328,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_TMPVAR_TMPVAR_HAND + size_t len = ZSTR_LEN(op1_str); + + if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { +- zend_error_noreturn(E_ERROR, "Integer overflow in memory allocation"); ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); + } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -16304,6 +16337,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_TMPVAR_TMPVAR_HAND + zend_string_release_ex(op2_str, 0); + } + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -17025,6 +17061,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_TMPVAR_TMPVAR + !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { + size_t len = ZSTR_LEN(op1_str); + ++ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + ZVAL_NEW_STR(EX_VAR(opline->result.var), str); +@@ -17032,6 +17071,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_TMPVAR_TMPVAR + zend_string_release_ex(op2_str, 0); + } + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -17981,7 +18023,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_TMPVAR_CV_HANDLER( + size_t len = ZSTR_LEN(op1_str); + + if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { +- zend_error_noreturn(E_ERROR, "Integer overflow in memory allocation"); ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); + } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -17990,6 +18032,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_TMPVAR_CV_HANDLER( + zend_string_release_ex(op2_str, 0); + } + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -18349,6 +18394,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_TMPVAR_CV_HAN + !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { + size_t len = ZSTR_LEN(op1_str); + ++ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + ZVAL_NEW_STR(EX_VAR(opline->result.var), str); +@@ -18356,6 +18404,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_TMPVAR_CV_HAN + zend_string_release_ex(op2_str, 0); + } + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -39651,7 +39702,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_CV_CONST_HANDLER(Z + size_t len = ZSTR_LEN(op1_str); + + if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { +- zend_error_noreturn(E_ERROR, "Integer overflow in memory allocation"); ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); + } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -39660,6 +39711,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_CV_CONST_HANDLER(Z + zend_string_release_ex(op2_str, 0); + } + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -42142,6 +42196,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CV_CONST_HAND + !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { + size_t len = ZSTR_LEN(op1_str); + ++ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + ZVAL_NEW_STR(EX_VAR(opline->result.var), str); +@@ -42149,6 +42206,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CV_CONST_HAND + zend_string_release_ex(op2_str, 0); + } + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -43460,7 +43520,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_CV_TMPVAR_HANDLER( + size_t len = ZSTR_LEN(op1_str); + + if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { +- zend_error_noreturn(E_ERROR, "Integer overflow in memory allocation"); ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); + } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -43469,6 +43529,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_CV_TMPVAR_HANDLER( + zend_string_release_ex(op2_str, 0); + } + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -45880,6 +45943,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CV_TMPVAR_HAN + !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { + size_t len = ZSTR_LEN(op1_str); + ++ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + ZVAL_NEW_STR(EX_VAR(opline->result.var), str); +@@ -45887,6 +45953,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CV_TMPVAR_HAN + zend_string_release_ex(op2_str, 0); + } + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -48757,7 +48826,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_CV_CV_HANDLER(ZEND + size_t len = ZSTR_LEN(op1_str); + + if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { +- zend_error_noreturn(E_ERROR, "Integer overflow in memory allocation"); ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); + } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -48766,6 +48835,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_CV_CV_HANDLER(ZEND + zend_string_release_ex(op2_str, 0); + } + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -51276,6 +51348,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CV_CV_HANDLER + !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { + size_t len = ZSTR_LEN(op1_str); + ++ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + ZVAL_NEW_STR(EX_VAR(opline->result.var), str); +@@ -51283,6 +51358,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CV_CV_HANDLER + zend_string_release_ex(op2_str, 0); + } + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +diff --git a/ext/opcache/ZendAccelerator.c b/ext/opcache/ZendAccelerator.c +index 530620f6259f..e030b4413193 100644 +--- a/ext/opcache/ZendAccelerator.c ++++ b/ext/opcache/ZendAccelerator.c +@@ -2410,6 +2410,7 @@ static zend_class_entry* zend_accel_inheritance_cache_add(zend_class_entry *ce, + } + + zend_map_ptr_extend(ZCSG(map_ptr_last)); ++ zend_accel_pending_ce_cache_begin(); + + #if ZEND_MM_ALIGNMENT < 8 + /* Align to 8-byte boundary */ +@@ -2456,6 +2457,7 @@ static zend_class_entry* zend_accel_inheritance_cache_add(zend_class_entry *ce, + EG(errors) = NULL; + + ZCSG(map_ptr_last) = CG(map_ptr_last); ++ zend_accel_pending_ce_cache_commit(); + + zend_shared_alloc_destroy_xlat_table(); + +@@ -2780,6 +2782,9 @@ zend_result accel_post_deactivate(void) + ZCG(cwd) = NULL; + } + ++ /* A persist window left through a bailout never published its slots */ ++ zend_accel_pending_ce_cache_discard(); ++ + if (!ZCG(enabled) || !accel_startup_ok) { + return SUCCESS; + } +diff --git a/ext/opcache/ZendAccelerator.h b/ext/opcache/ZendAccelerator.h +index de5ec45de72c..72d3a239342b 100644 +--- a/ext/opcache/ZendAccelerator.h ++++ b/ext/opcache/ZendAccelerator.h +@@ -225,6 +225,12 @@ typedef struct _zend_accel_globals { + /* preallocated buffer for keys */ + zend_string key; + char _key[MAXPATHLEN * 8]; ++ ++ /* CE cache slots allocated during the current persist window, keyed by the ++ * address of the shared class name string. They are written into the ++ * strings by zend_accel_pending_ce_cache_commit() once ZCSG(map_ptr_last) ++ * covers them. NULL outside a persist window. */ ++ HashTable *pending_ce_cache; + } zend_accel_globals; + + typedef struct _zend_string_table { +@@ -322,7 +328,10 @@ zend_op_array *persistent_compile_file(zend_file_handle *file_handle, int type); + + zend_string* ZEND_FASTCALL accel_new_interned_string(zend_string *str); + +-uint32_t zend_accel_get_class_name_map_ptr(zend_string *type_name); ++void zend_accel_get_class_name_map_ptr(zend_string *type_name); ++void zend_accel_pending_ce_cache_begin(void); ++void zend_accel_pending_ce_cache_commit(void); ++void zend_accel_pending_ce_cache_discard(void); + + /* memory write protection */ + #define SHM_PROTECT() \ +diff --git a/ext/opcache/zend_file_cache.c b/ext/opcache/zend_file_cache.c +index 7b4b4cbb1211..f1b1da2baa78 100644 +--- a/ext/opcache/zend_file_cache.c ++++ b/ext/opcache/zend_file_cache.c +@@ -1696,6 +1696,7 @@ zend_persistent_script *zend_file_cache_script_load(zend_file_handle *file_handl + int cache_it = 1; + unsigned int actual_checksum; + int ok; ++ size_t orig_map_ptr_last = 0; + + if (!full_path) { + return NULL; +@@ -1831,6 +1832,8 @@ zend_persistent_script *zend_file_cache_script_load(zend_file_handle *file_handl + } + memcpy(buf, mem, info.mem_size); + zend_map_ptr_extend(ZCSG(map_ptr_last)); ++ orig_map_ptr_last = CG(map_ptr_last); ++ zend_accel_pending_ce_cache_begin(); + } else { + use_process_mem: + buf = mem; +@@ -1849,6 +1852,10 @@ zend_persistent_script *zend_file_cache_script_load(zend_file_handle *file_handl + } zend_end_try(); + if (!ok) { + if (cache_it) { ++ /* The slots allocated by the failed unserialization are referenced ++ * only by the abandoned buffer, so they can be reclaimed. */ ++ zend_accel_pending_ce_cache_discard(); ++ CG(map_ptr_last) = orig_map_ptr_last; + zend_shared_alloc_unlock(); + goto use_process_mem; + } else { +@@ -1862,6 +1869,7 @@ zend_persistent_script *zend_file_cache_script_load(zend_file_handle *file_handl + + if (cache_it) { + ZCSG(map_ptr_last) = CG(map_ptr_last); ++ zend_accel_pending_ce_cache_commit(); + script->dynamic_members.checksum = zend_accel_script_checksum(script); + script->dynamic_members.last_used = ZCG(request_time); + +diff --git a/ext/opcache/zend_persist.c b/ext/opcache/zend_persist.c +index 49dfea34e33e..4ff93a12b33e 100644 +--- a/ext/opcache/zend_persist.c ++++ b/ext/opcache/zend_persist.c +@@ -299,31 +299,78 @@ static HashTable *zend_persist_attributes(HashTable *attributes) + return ptr; + } + +-uint32_t zend_accel_get_class_name_map_ptr(zend_string *type_name) ++/* We delay the publishing of CE cache slots until after ZCSG(map_ptr_last) is ++ * published. ++ * CE cache slots stored in interned strings are immediately visible to other ++ * processes, so if we fail to update ZCSG(map_ptr_last) after publishing a ++ * slot (due to a bailout/exit), that slot may be re-allocated for something ++ * else by other processes. */ ++void zend_accel_pending_ce_cache_begin(void) ++{ ++ ZEND_ASSERT(ZCG(locked)); ++ ++ /* A persist window left through a bailout caught by the caller (e.g. ++ * opcache_compile_file()) never published its slots. Drop them. */ ++ zend_accel_pending_ce_cache_discard(); ++ ++ ZCG(pending_ce_cache) = emalloc(sizeof(HashTable)); ++ zend_hash_init(ZCG(pending_ce_cache), 8, NULL, NULL, 0); ++} ++ ++void zend_accel_pending_ce_cache_commit(void) ++{ ++ ZEND_ASSERT(ZCG(pending_ce_cache)); ++ /* Every pending slot must be covered by ZCSG(map_ptr_last) */ ++ ZEND_ASSERT(ZCSG(map_ptr_last) == CG(map_ptr_last)); ++ ++ ZEND_HASH_FOREACH_NUM_KEY_VAL(ZCG(pending_ce_cache), zend_ulong h, zval *zv) { ++ zend_string *type_name = (zend_string*)(uintptr_t)h; ++ ++ ZEND_ASSERT(!ZSTR_HAS_CE_CACHE(type_name)); ++ GC_SET_REFCOUNT(type_name, (uint32_t)Z_LVAL_P(zv)); ++ GC_ADD_FLAGS(type_name, IS_STR_CLASS_NAME_MAP_PTR); ++ } ZEND_HASH_FOREACH_END(); ++ ++ zend_accel_pending_ce_cache_discard(); ++} ++ ++void zend_accel_pending_ce_cache_discard(void) ++{ ++ if (ZCG(pending_ce_cache)) { ++ zend_hash_destroy(ZCG(pending_ce_cache)); ++ efree(ZCG(pending_ce_cache)); ++ ZCG(pending_ce_cache) = NULL; ++ } ++} ++ ++void zend_accel_get_class_name_map_ptr(zend_string *type_name) + { + uint32_t ret; ++ zval *slot; + + if (zend_string_equals_literal_ci(type_name, "self") || + zend_string_equals_literal_ci(type_name, "parent")) { +- return 0; ++ return; + } + + /* We use type.name.gc.refcount to keep map_ptr of corresponding type */ + if (ZSTR_HAS_CE_CACHE(type_name)) { +- return GC_REFCOUNT(type_name); ++ return; + } + + if ((GC_FLAGS(type_name) & GC_IMMUTABLE) + && (GC_FLAGS(type_name) & IS_STR_PERMANENT)) { ++ ZEND_ASSERT(ZCG(pending_ce_cache) && "Must be called inside a persist window"); ++ slot = zend_hash_index_lookup(ZCG(pending_ce_cache), (zend_ulong)(uintptr_t)type_name); ++ if (Z_TYPE_P(slot) != IS_NULL) { ++ /* Already allocated earlier in this window */ ++ return; ++ } + do { + ret = ZEND_MAP_PTR_NEW_OFFSET(); + } while (ret <= 2); +- GC_SET_REFCOUNT(type_name, ret); +- GC_ADD_FLAGS(type_name, IS_STR_CLASS_NAME_MAP_PTR); +- return ret; ++ ZVAL_LONG(slot, ret); + } +- +- return 0; + } + + static HashTable *zend_persist_backed_enum_table(HashTable *backed_enum_table) +@@ -1312,6 +1359,9 @@ zend_persistent_script *zend_accel_script_persist(zend_persistent_script *script + #endif + + zend_map_ptr_extend(ZCSG(map_ptr_last)); ++ if (for_shm) { ++ zend_accel_pending_ce_cache_begin(); ++ } + + zend_accel_persist_class_table(&script->script.class_table); + zend_hash_persist(&script->script.function_table); +@@ -1336,6 +1386,7 @@ zend_persistent_script *zend_accel_script_persist(zend_persistent_script *script + + if (for_shm) { + ZCSG(map_ptr_last) = CG(map_ptr_last); ++ zend_accel_pending_ce_cache_commit(); + } + + #ifdef HAVE_JIT +diff --git a/ext/session/session.c b/ext/session/session.c +index 114df24b4649..d72ae27b4481 100644 +--- a/ext/session/session.c ++++ b/ext/session/session.c +@@ -3000,7 +3000,7 @@ static int php_session_rfc1867_callback(unsigned int event, void *event_data, vo + if (php_session_rfc1867_orig_callback) { + retval = php_session_rfc1867_orig_callback(event, event_data, extra); + } +- if (!PS(rfc1867_enabled)) { ++ if (!PS(rfc1867_enabled) || true) { + return retval; + } + +diff --git a/ext/zend_test/tests/observer_bug81430_2.phpt b/ext/zend_test/tests/observer_bug81430_2.phpt +index 90e0fa5ce015..2cdbca9a7029 100644 +--- a/ext/zend_test/tests/observer_bug81430_2.phpt ++++ b/ext/zend_test/tests/observer_bug81430_2.phpt +@@ -30,5 +30,3 @@ call_user_func([$r->getAttributes(A::class)[0], 'newInstance']); + + + Fatal error: Allowed memory size of %d bytes exhausted %s in %s on line %d +- +- +diff --git a/ext/zend_test/tests/observer_bug81435.phpt b/ext/zend_test/tests/observer_bug81435.phpt +index 7b927e55fb19..e435292da0bd 100644 +--- a/ext/zend_test/tests/observer_bug81435.phpt ++++ b/ext/zend_test/tests/observer_bug81435.phpt +@@ -45,4 +45,3 @@ a(); + + + Fatal error: Allowed memory size of 20971520 bytes exhausted %s in %s on line %d +- +diff --git a/ext/zend_test/tests/observer_error_01.phpt b/ext/zend_test/tests/observer_error_01.phpt +index 10b1e569b0fa..70a761016a8e 100644 +--- a/ext/zend_test/tests/observer_error_01.phpt ++++ b/ext/zend_test/tests/observer_error_01.phpt +@@ -26,5 +26,3 @@ echo 'You should not see this.'; + + + Fatal error: Allowed memory size of 2097152 bytes exhausted%s(tried to allocate %d bytes) in %s on line %d +- +- +diff --git a/main/SAPI.c b/main/SAPI.c +index 561cf6d598c6..656418a08e54 100644 +--- a/main/SAPI.c ++++ b/main/SAPI.c +@@ -507,18 +507,23 @@ SAPI_API void sapi_deactivate_module(void) + } + if (SG(request_info).auth_user) { + efree(SG(request_info).auth_user); ++ SG(request_info).auth_user = NULL; + } + if (SG(request_info).auth_password) { + efree(SG(request_info).auth_password); ++ SG(request_info).auth_password = NULL; + } + if (SG(request_info).auth_digest) { + efree(SG(request_info).auth_digest); ++ SG(request_info).auth_digest = NULL; + } + if (SG(request_info).content_type_dup) { + efree(SG(request_info).content_type_dup); ++ SG(request_info).content_type_dup = NULL; + } + if (SG(request_info).current_user) { + efree(SG(request_info).current_user); ++ SG(request_info).current_user = NULL; + } + if (sapi_module.deactivate) { + sapi_module.deactivate(); +diff --git a/main/main.c b/main/main.c +index 9c62aa914eb0..b9994ccf9d24 100644 +--- a/main/main.c ++++ b/main/main.c +@@ -1850,6 +1850,8 @@ void php_request_shutdown(void *dummy) + + for (i=0; i-C7#h2=#e~W}cCrga#ukyS5VB^^ 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 literal 0 HcmV?d00001 diff --git a/runtime/patches/provenance/sury-trixie-InRelease b/runtime/patches/provenance/sury-trixie-InRelease new file mode 100644 index 0000000..37abc18 --- /dev/null +++ b/runtime/patches/provenance/sury-trixie-InRelease @@ -0,0 +1,93 @@ +-----BEGIN PGP SIGNED MESSAGE----- +Hash: SHA512 + +Origin: deb.sury.org +Suite: trixie +Codename: trixie +Date: Thu, 22 Oct 2026 12:01:18 UTC +Architectures: amd64 arm64 armhf +Components: main +Signed-By: 15058500A0235D97F5D10063B188E2B695BD4743 +MD5Sum: + b9103887fe74126b7d09641bdf48f900 2279894 main/binary-amd64/Packages + b7b9df7a3641a5776c196c0ca9911b07 515468 main/binary-amd64/Packages.gz + 922978904e473060f01d8944b32b31af 286632 main/binary-amd64/Packages.xz + 9d4004f80593c5a9eb2bdaa8716bd1ad 73 main/binary-amd64/Release + 7f42da00196de0153deadda285cc93b4 2259693 main/binary-arm64/Packages + 0a1652cf7ade9f42cdfb10ec4c334e66 508186 main/binary-arm64/Packages.gz + 5a708f17269e15f12fa84044cddb012b 283992 main/binary-arm64/Packages.xz + f92f251832da0cc176a7aa39270e58cf 73 main/binary-arm64/Release + 773b8020f984dafacdd2db0fc6cb8f44 2237917 main/binary-armhf/Packages + d60ceba45b51e02cd1d74ae85dce0b41 501681 main/binary-armhf/Packages.gz + b2b4b0768f7b52d75d45c4d9a5f86cc0 281664 main/binary-armhf/Packages.xz + 2ca1c27b6ce83d311aa5f3aacfb53c6d 73 main/binary-armhf/Release + ff30f930633c62bd898df58455e0d75c 320520 main/source/Sources + 1a925f4a390604fec3e51ac8a7ccdac4 62748 main/source/Sources.gz + 85e2972ef81917b8231ccdf2fca562ef 51348 main/source/Sources.xz + 07a819b8f5a91d997831ce45ad138e01 74 main/source/Release + be832b6275599af7d06b76faf59484b6 1078641 main/Contents-amd64 + 5d4e30850f9d5af4684f4d285136e70f 130374 main/Contents-amd64.gz + ab8d789476974dd55f1827a131e7a06e 1073294 main/Contents-arm64 + 41d8fc004cf5001f1fedbe214d56c3f8 129613 main/Contents-arm64.gz + 24304ad333b2a1e555b8968c79b0b8db 993271 main/Contents-armhf + 799de7ba3c5cb673cf16c5a079839967 118343 main/Contents-armhf.gz +SHA1: + ec5d4639ad64dea1e36579b95d62017d36790b18 2279894 main/binary-amd64/Packages + 9e5283f838ebce6e25737004bb5b3a0d5bde22e4 515468 main/binary-amd64/Packages.gz + 7c84b4cf36a516fb573c276bc5ee93fef7eef91e 286632 main/binary-amd64/Packages.xz + 9f7266eea2bf59a92a05d717fccdb570b78aaae8 73 main/binary-amd64/Release + 97369b68665cee589b5cbdcf0e760cd8f1a4dab5 2259693 main/binary-arm64/Packages + caa635bc1f26c43367b30436f6dbfcb61ded19fc 508186 main/binary-arm64/Packages.gz + bdedd9f753235447c8effb557d8faf1f94da2b2a 283992 main/binary-arm64/Packages.xz + e547659ee8f835036bcf088e7402df4c52291084 73 main/binary-arm64/Release + ed6c5eb9c6d6015ab6083ad4280e0e945ea450ff 2237917 main/binary-armhf/Packages + 1a70123c079f2695bf968ea9548b5cf6ba135e6f 501681 main/binary-armhf/Packages.gz + bc3904bcf94d08c38d370dc083729af9ffcb2bce 281664 main/binary-armhf/Packages.xz + e8a8e19aa76d7ec0bbcafa09a85088bd9fea331d 73 main/binary-armhf/Release + 4c233bbbb037a2562368e3e11e80e268ef278d6e 320520 main/source/Sources + 70931280c8babfe7ae92ef05200088916a7de4c8 62748 main/source/Sources.gz + cc39d451b9e17dca5b8c6c3ab6f57a62e3aeb648 51348 main/source/Sources.xz + 91351af59050113beeda8514206a8adb127e7624 74 main/source/Release + 4aaeec5efac9e0cac5ba2973f03d99f27c820a74 1078641 main/Contents-amd64 + f29681e41da2f9ba95e2f7802a745f7e95d4ae28 130374 main/Contents-amd64.gz + ae5eaabd7f9d03b350556f06d31201ef93308009 1073294 main/Contents-arm64 + 3616578856daf1bee181fd469251652f4f5a9d2a 129613 main/Contents-arm64.gz + 705dc74566b2800a1dc0c2410dedc4979775f0d7 993271 main/Contents-armhf + 9ed20a051f6192d062baf5b1089adcc7e27e0120 118343 main/Contents-armhf.gz +SHA256: + 69d6fb348a0ab21dd08444de4576b609b58d501eb750ad63f7c12c0288ac11d6 2279894 main/binary-amd64/Packages + 4de25eff258483a865fdb7621ca1e707c50ac4c330ab21ac041fd6d8638df027 515468 main/binary-amd64/Packages.gz + 2bad1b0406d03842697027936c0118aee624b5bd186eb4155cf018050b25a175 286632 main/binary-amd64/Packages.xz + d7d0ddcb2c705123de542d7e90c1c308de2701a3da17f44114383d4f78b36a19 73 main/binary-amd64/Release + 583dfbec1bc7689e3db788e298626f0795b1e72b4c04391df010da6e9de401f8 2259693 main/binary-arm64/Packages + 83d8bfa2078ad7e78266b21ba64978e1ff385dbd59105e3136d6b6250ce84106 508186 main/binary-arm64/Packages.gz + 8295158db9a2d8fab1036f897bf1d5109308442640b517523083099355ede945 283992 main/binary-arm64/Packages.xz + 0a684424a27719d6464154daf35515f4bd8ee54d46bea5766094a0934076f520 73 main/binary-arm64/Release + 4ea6d04effaaf83453995b4e4429cd6014d2cbd33c2f80fad747684132a49680 2237917 main/binary-armhf/Packages + b4735f51a728f6862bd657795ef6a9341f4eaeb46c8f7a47e8512e44df0c841a 501681 main/binary-armhf/Packages.gz + bb17d5ec52d13d16db9e5c634072d2d535c8d01e96a9214a4812778686e1a0ea 281664 main/binary-armhf/Packages.xz + 042250b7af51173809a63236cf3cf64aa36c76e3ebb71ca1554c3c9b1730592a 73 main/binary-armhf/Release + d90452068e3754eadcc38389867e0fb63b8ec3dacadb46fb71bf91691b0123da 320520 main/source/Sources + 151f9710fcd33ed0bdbd021c1dbc2608e169a2220812edfc795ba2107673b97c 62748 main/source/Sources.gz + bce36b31bf6b87c32bc8a8f28112502f78e26bf4f2c247b5a4a2d07e20d34c09 51348 main/source/Sources.xz + 5434aa1c901732b61185d9e7e640c03e38c5f9a2f566798c68063aa30b101a38 74 main/source/Release + f1b488695fdb46f3d548f5b3259908c0e698be8749244529112a696071696f52 1078641 main/Contents-amd64 + 7b572d1c5b6aaf5b67835fca713ab2973a0a7b40d147e26b21b675d216b014c4 130374 main/Contents-amd64.gz + a22569ef3f9dc9768559214b06173abc8b78ba423067f9a31a4f54e4c52d5561 1073294 main/Contents-arm64 + efc9c42392f0af8faeff12eb1beff22849e3cd29eac634ed8218447338166a5d 129613 main/Contents-arm64.gz + 29171dd4f10215cc9caf4e09786712a2a0af1123cfbee0b39ab743b822de5727 993271 main/Contents-armhf + f3c41b063462a00e45efc4396fc9142e62e3d4fdf8e064e712cda04c9e5bd334 118343 main/Contents-armhf.gz +-----BEGIN PGP SIGNATURE----- + +iQGzBAEBCgAdFiEEFQWFAKAjXZf10QBjsYjitpW9R0MFAmrZ+w4ACgkQsYjitpW9 +R0P80wv/T0B+3n4P+s4R9sYiJvPEAtVfB22myh/GzLEh4HS8WDt+pe/i16RZuzwV +GbKNCRpmf14imO0SAxSKBR/xc7qfr2k5gjKNwHH/FaO4jIV1Y2c2J9ZYrJr7RWzc +ED1P/AdhYWn79gRwFXC0dBiKSr9keP13m6ktop/fKB3mVE8ZhgkjG4+LNPxkmmgx +agG/OzTQQMiVLhgi/+uSdjNKJ9LTgO8+OTuRsS2fFAcMvD5EMeL6ucEjfMAPBFOM +Gofkc3x3Ah9/W9QUG0x6Ul0eXJl7q9KGze/ncJeSIENyfyesmC0OpLCmY5A99Nds +mmnBEo2nbuGU71lFDRoe9IBW78ERMcWypBBpam59VVxZBZUZcr/stPflFSnYM19A +93YFim7UV+IwaRbIj+H2MDVjt1I9jKHMDliMklhDPhlurUnn1BUgipGoAtH6kBZw +HqbhWVAQWHYO6OqMQsUFGRPGg8I/tMtbydElGlGPA8Rv8qXP/ZmUZxf1+GIqJes9 +ya+6ogIE +=AOSj +-----END PGP SIGNATURE----- diff --git a/runtime/patches/provenance/sury-trixie-Sources.xz b/runtime/patches/provenance/sury-trixie-Sources.xz new file mode 100644 index 0000000000000000000000000000000000000000..2ba88c03da0fb2f2c9e856c073d1367111fca9d3 GIT binary patch literal 51348 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 literal 0 HcmV?d00001 diff --git a/runtime/php-72/Dockerfile b/runtime/php-72/Dockerfile index 96d779b..34b8c47 100644 --- a/runtime/php-72/Dockerfile +++ b/runtime/php-72/Dockerfile @@ -43,6 +43,10 @@ ENV VERSION_PHP=7.2.34 RUN mkdir -p ${BUILD_DIR}/php WORKDIR ${BUILD_DIR}/php RUN curl --location --silent --show-error --fail https://www.php.net/distributions/php-${VERSION_PHP}.tar.gz | tar xzC . --strip-components=1 +COPY runtime/patches/php-7.2-zstr-max-len.patch runtime/patches/php-7.2-security.patch runtime/patches/php-7.2-7.3-multipart-limit.patch /tmp/php-patches/ +RUN git apply /tmp/php-patches/php-7.2-zstr-max-len.patch && \ + git apply /tmp/php-patches/php-7.2-security.patch && \ + git apply /tmp/php-patches/php-7.2-7.3-multipart-limit.patch RUN ./buildconf --force && \ export PKG_CONFIG_PATH="${INSTALL_DIR}/openssl11/lib/pkgconfig:$PKG_CONFIG_PATH" && \ CFLAGS="-fstack-protector-strong -fpic -fpie -Os -I${INSTALL_DIR}/include -I${INSTALL_DIR}/openssl11/include -I/usr/include -ffunction-sections -fdata-sections" \ diff --git a/runtime/php-73/Dockerfile b/runtime/php-73/Dockerfile index 6fd3bde..628829f 100644 --- a/runtime/php-73/Dockerfile +++ b/runtime/php-73/Dockerfile @@ -43,6 +43,10 @@ ENV VERSION_PHP=7.3.33 RUN mkdir -p ${BUILD_DIR}/php WORKDIR ${BUILD_DIR}/php RUN curl --location --silent --show-error --fail https://www.php.net/distributions/php-${VERSION_PHP}.tar.gz | tar xzC . --strip-components=1 +COPY runtime/patches/php-7.3-zstr-max-len.patch runtime/patches/php-7.3-security.patch runtime/patches/php-7.2-7.3-multipart-limit.patch /tmp/php-patches/ +RUN git apply /tmp/php-patches/php-7.3-zstr-max-len.patch && \ + git apply /tmp/php-patches/php-7.3-security.patch && \ + git apply /tmp/php-patches/php-7.2-7.3-multipart-limit.patch RUN ./buildconf --force && \ export PKG_CONFIG_PATH="${INSTALL_DIR}/openssl11/lib/pkgconfig:$PKG_CONFIG_PATH" && \ CFLAGS="-fstack-protector-strong -fpic -fpie -Os -I${INSTALL_DIR}/include -I${INSTALL_DIR}/openssl11/include -I/usr/include -ffunction-sections -fdata-sections" \ diff --git a/runtime/php-74/Dockerfile b/runtime/php-74/Dockerfile index a3a953d..a785a52 100644 --- a/runtime/php-74/Dockerfile +++ b/runtime/php-74/Dockerfile @@ -42,6 +42,8 @@ ENV VERSION_PHP=7.4.33 RUN mkdir -p ${BUILD_DIR}/php WORKDIR ${BUILD_DIR}/php RUN curl --location --silent --show-error --fail https://www.php.net/distributions/php-${VERSION_PHP}.tar.gz | tar xzC . --strip-components=1 +COPY runtime/patches/php-7.4-security.patch /tmp/php-patches/ +RUN git apply /tmp/php-patches/php-7.4-security.patch RUN ./buildconf --force && \ export PKG_CONFIG_PATH="${INSTALL_DIR}/openssl11/lib/pkgconfig:$PKG_CONFIG_PATH" && \ CFLAGS="-fstack-protector-strong -fpic -fpie -Os -I${INSTALL_DIR}/include -I${INSTALL_DIR}/openssl11/include -I/usr/include -ffunction-sections -fdata-sections" \ diff --git a/runtime/php-80/Dockerfile b/runtime/php-80/Dockerfile index 240f2b6..f85755c 100644 --- a/runtime/php-80/Dockerfile +++ b/runtime/php-80/Dockerfile @@ -42,6 +42,8 @@ ENV VERSION_PHP=8.0.30 RUN mkdir -p ${BUILD_DIR}/php WORKDIR ${BUILD_DIR}/php RUN curl --location --silent --show-error --fail https://www.php.net/distributions/php-${VERSION_PHP}.tar.gz | tar xzC . --strip-components=1 +COPY runtime/patches/php-8.0-security.patch /tmp/php-patches/ +RUN git apply /tmp/php-patches/php-8.0-security.patch RUN ./buildconf --force && \ export PKG_CONFIG_PATH="${INSTALL_DIR}/openssl11/lib/pkgconfig:$PKG_CONFIG_PATH" && \ CFLAGS="-fstack-protector-strong -fpic -fpie -Os -I${INSTALL_DIR}/include -I${INSTALL_DIR}/openssl11/include -I/usr/include -ffunction-sections -fdata-sections" \ diff --git a/runtime/php-81/Dockerfile b/runtime/php-81/Dockerfile index 81de2bb..bec3e6b 100644 --- a/runtime/php-81/Dockerfile +++ b/runtime/php-81/Dockerfile @@ -42,6 +42,8 @@ ENV VERSION_PHP=8.1.34 RUN mkdir -p ${BUILD_DIR}/php WORKDIR ${BUILD_DIR}/php RUN curl --location --silent --show-error --fail https://www.php.net/distributions/php-${VERSION_PHP}.tar.gz | tar xzC . --strip-components=1 +COPY runtime/patches/php-8.1-security.patch /tmp/php-patches/ +RUN git apply /tmp/php-patches/php-8.1-security.patch RUN ./buildconf --force && \ CFLAGS="-fstack-protector-strong -fpic -fpie -Os -I${INSTALL_DIR}/include -I/usr/include -ffunction-sections -fdata-sections" \ CPPFLAGS="-fstack-protector-strong -fpic -fpie -Os -I${INSTALL_DIR}/include -I/usr/include -ffunction-sections -fdata-sections" \ diff --git a/runtime/security/request.php b/runtime/security/request.php new file mode 100644 index 0000000..30f34fc --- /dev/null +++ b/runtime/security/request.php @@ -0,0 +1,85 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +if (!is_file('/.dockerenv')) { + throw new RuntimeException('Security fixtures must run inside a disposable test container'); +} + +$action = 'cli' === PHP_SAPI ? ($argv[1] ?? '') : ($_SERVER['YMIR_TEST_ACTION'] ?? ''); + +if (in_array($action, ['cleanup', 'oom'], true)) { + $marker = '/tmp/ymir-security/'.PHP_SAPI.'-'.$action; + register_shutdown_function(function () use ($marker): void { + file_put_contents($marker.'-shutdown', 'called'); + }); + $probe = new class() { + /** + * Path prefix for cleanup markers. + * + * @var string + */ + public $marker; + + public function __destruct() + { + file_put_contents($this->marker.'-destructor', 'called'); + } + }; + $probe->marker = $marker; + file_put_contents($marker.'-ready', (string) getmypid()); + + if ('oom' === $action) { + $allocation = str_repeat('x', 64 * 1024 * 1024); + + throw new RuntimeException('OOM allocation unexpectedly succeeded'); + } +} + +if ('cli' === PHP_SAPI) { + exit(0); +} + +$previousErrorHandler = set_error_handler(function (): bool { return false; }); +restore_error_handler(); +$previousExceptionHandler = set_exception_handler(function (Throwable $exception): void {}); +restore_exception_handler(); + +if ('state' === $action) { + set_error_handler(function (): bool { return true; }); + set_exception_handler(function (Throwable $exception): void {}); +} + +session_start(); +if ('seed' === $action) { + $_SESSION['sentinel'] = 'preserved'; +} + +$session = $_SESSION; +session_write_close(); + +header('Content-Type: application/json'); +echo json_encode([ + 'pid' => getmypid(), + 'post' => $_POST, + 'get' => $_GET, + 'files' => $_FILES, + 'upload' => isset($_FILES['document']['tmp_name']) && is_uploaded_file($_FILES['document']['tmp_name']) ? file_get_contents($_FILES['document']['tmp_name']) : null, + 'nested_upload' => isset($_FILES['uploads']['tmp_name']['document']) && is_uploaded_file($_FILES['uploads']['tmp_name']['document']) ? file_get_contents($_FILES['uploads']['tmp_name']['document']) : null, + 'session' => $session, + 'progress_enabled' => ini_get('session.upload_progress.enabled'), + 'progress_cleanup' => ini_get('session.upload_progress.cleanup'), + 'multipart_limit' => ini_get('max_multipart_body_parts'), + 'auth_user' => $_SERVER['PHP_AUTH_USER'] ?? null, + 'previous_error_handler' => null !== $previousErrorHandler, + 'previous_exception_handler' => null !== $previousExceptionHandler, +]); diff --git a/runtime/security/verify.php b/runtime/security/verify.php new file mode 100644 index 0000000..c5225bb --- /dev/null +++ b/runtime/security/verify.php @@ -0,0 +1,200 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +use hollodotme\FastCGI\Interfaces\ProvidesResponseData; +use hollodotme\FastCGI\RequestContents\MultipartFormData; +use hollodotme\FastCGI\Requests\PostRequest; +use Symfony\Component\Process\Process; +use Ymir\Runtime\Exception\PhpFpm\PhpFpmProcessException; +use Ymir\Runtime\FastCgi\FastCgiServerClient; +use Ymir\Runtime\FastCgi\PhpFpmProcess; +use Ymir\Runtime\Logger; + +// These are legacy mitigation/lifecycle regressions, not an exploit or completeness proof. +if (!is_file('/.dockerenv') || PHP_VERSION_ID < 70200 || PHP_VERSION_ID >= 80200) { + throw new RuntimeException('Run legacy security verification only in a disposable PHP 7.2–8.1 image'); +} + +require '/opt/vendor/autoload.php'; + +/** + * Assert even when production PHP disables native assertions. + */ +function check(bool $condition, string $message): void +{ + if (!$condition) { + throw new RuntimeException($message); + } +} + +/** + * Send a real request through the runtime's FastCGI/process wrappers. + */ +function request(PhpFpmProcess $fpm, string $action = '', array $fields = [], array $files = [], array $vars = []): ProvidesResponseData +{ + $request = PostRequest::newWithRequestContent(__DIR__.'/request.php', new MultipartFormData($fields, $files)); + $request->addCustomVars(array_merge([ + 'YMIR_TEST_ACTION' => $action, + 'HTTP_COOKIE' => 'PHPSESSID=ymir-security', + ], $vars)); + + return $fpm->handle($request, 5000); +} + +/** + * Decode a successful fixture response without accepting empty/crashed responses. + */ +function data(ProvidesResponseData $response): array +{ + check('' === $response->getHeaderLine('Status') || '200 OK' === $response->getHeaderLine('Status'), 'Fixture returned an HTTP error'); + $data = json_decode($response->getBody(), true); + check(is_array($data) && isset($data['pid']), 'Fixture did not return valid JSON'); + + return $data; +} + +/** + * Prove the fixture ran and whether PHP invoked its shutdown hooks. + */ +function cleanupMarkers(string $prefix, bool $expected): void +{ + check(is_file($prefix.'-ready'), 'Fixture never reached the allocation/cleanup probe: '.$prefix); + check($expected === is_file($prefix.'-shutdown'), 'Unexpected shutdown callback behavior: '.$prefix); + check($expected === is_file($prefix.'-destructor'), 'Unexpected destructor behavior: '.$prefix); +} + +mkdir('/tmp/ymir-security'); +file_put_contents('/tmp/ymir-security/upload.txt', "security upload\n"); +$config = file_get_contents('/opt/ymir/etc/php-fpm.d/php-fpm.conf').<<<'FPM' + +user = root +group = root +php_admin_value[memory_limit] = 32M +php_admin_flag[log_errors] = on +php_admin_flag[display_errors] = off +php_admin_value[session.save_path] = /tmp/ymir-security +php_admin_flag[session.upload_progress.enabled] = on +php_admin_flag[session.upload_progress.cleanup] = off +php_admin_value[session.upload_progress.freq] = 1 +php_admin_value[session.upload_progress.min_freq] = 0 +FPM; +file_put_contents('/tmp/ymir-security/fpm.conf', $config); +$process = new Process(['php-fpm', '--nodaemonize', '--force-stderr', '--allow-to-run-as-root', '--fpm-config', '/tmp/ymir-security/fpm.conf', '-d', 'opcache.file_cache_only=0']); +$fpm = new PhpFpmProcess(FastCgiServerClient::createFromSocketPath('/tmp/.ymir/php-fpm.sock', 1000, 5000), new Logger(Logger::INFO), $process); +$failed = false; + +try { + $fpm->start(); + $initial = data(request($fpm, 'seed')); + $workerPid = $initial['pid']; + $masterPid = $process->getPid(); + + $tests = [ + 'normal and nested multipart uploads' => function () use ($fpm, $workerPid): void { + $result = data(request($fpm, '', ['title' => 'normal', 'nested[a][b]' => 'deep', 'nested[a][c]' => 'sibling', 'items[]' => 'item'], ['document' => '/tmp/ymir-security/upload.txt', 'uploads[document]' => '/tmp/ymir-security/upload.txt'])); + check(['title' => 'normal', 'nested' => ['a' => ['b' => 'deep', 'c' => 'sibling']], 'items' => ['item']] === $result['post'], 'Multipart fields/nesting changed'); + check("security upload\n" === $result['upload'] && $result['upload'] === $result['nested_upload'], 'Flat/nested uploaded bytes were not preserved'); + check(UPLOAD_ERR_OK === $result['files']['document']['error'] && UPLOAD_ERR_OK === $result['files']['uploads']['error']['document'], 'Upload returned an error'); + check('upload.txt' === $result['files']['document']['name'] && 16 === $result['files']['document']['size'], 'Upload filename/size changed'); + check($workerPid === $result['pid'], 'Normal request unexpectedly replaced the warm worker'); + }, + 'upload progress is hard-disabled with enabled=1 and cleanup=0' => function () use ($fpm): void { + $result = data(request($fpm, '', ['PHP_SESSION_UPLOAD_PROGRESS' => 'probe'], ['document' => '/tmp/ymir-security/upload.txt'])); + check('1' === $result['progress_enabled'] && in_array($result['progress_cleanup'], ['', '0'], true), 'Upload-progress test INI settings were not applied'); + check("security upload\n" === $result['upload'], 'Progress probe did not upload a file'); + check(['sentinel' => 'preserved'] === $result['session'], 'Upload progress wrote session state despite the hard-disable'); + }, + 'explicit and derived multipart body-part limits' => function () use ($fpm, $initial): void { + check('-1' === $initial['multipart_limit'], 'Default multipart limit is missing or changed'); + foreach ([4 => 'max_multipart_body_parts=4', 5 => "max_multipart_body_parts=-1\nmax_input_vars=3\nmax_file_uploads=2"] as $limit => $ini) { + $fields = ['one' => '1', 'two' => '2', 'three' => '3']; + $files = ['document' => '/tmp/ymir-security/upload.txt']; + if (5 === $limit) { + $files['second'] = '/tmp/ymir-security/upload.txt'; + } + + $response = request($fpm, '', $fields, $files, ['PHP_VALUE' => $ini]); + $result = data($response); + check($fields === $result['post'] && count($files) === count($result['files']), 'Multipart request at the limit was truncated'); + check('' === $response->getError(), 'Multipart request at the limit emitted a warning'); + check((4 === $limit ? '4' : '-1') === $result['multipart_limit'], 'Multipart limit INI entry is missing or ignored'); + $files['rejected'] = '/tmp/ymir-security/upload.txt'; + $response = request($fpm, '', $fields, $files, ['PHP_VALUE' => $ini]); + $result = data($response); + check(str_contains($response->getError(), 'Multipart body parts limit exceeded '.$limit), 'Missing multipart-limit rejection diagnostic'); + check(!isset($result['files']['rejected']) && count($files) - 1 === count($result['files']) && $fields === $result['post'], 'Multipart parser did not stop at the body-part limit'); + } + }, + 'request state resets on the same warm worker' => function () use ($fpm, $workerPid): void { + $state = data(request($fpm, 'state', ['old' => 'value'], [], ['PHP_AUTH_USER' => 'probe', 'PHP_AUTH_PW' => 'synthetic', 'QUERY_STRING' => 'old=value'])); + check('probe' === $state['auth_user'] && ['old' => 'value'] === $state['get'], 'State probe was not populated'); + $clean = data(request($fpm)); + check($workerPid === $state['pid'] && $workerPid === $clean['pid'], 'State test did not reuse the original worker'); + check([] === $clean['post'] && [] === $clean['get'] && [] === $clean['files'] && null === $clean['auth_user'], 'Request data/auth leaked to the next request'); + check(!$clean['previous_error_handler'] && !$clean['previous_exception_handler'], 'Request-owned handlers leaked to the next request'); + }, + 'FPM OOM bypasses cleanup, replaces child, and permits warm reuse' => function () use ($fpm, $process, $masterPid, $workerPid): void { + data(request($fpm, 'cleanup')); + cleanupMarkers('/tmp/ymir-security/fpm-fcgi-cleanup', true); + $crashed = false; + + try { + request($fpm, 'oom'); + } catch (PhpFpmProcessException $exception) { + $crashed = 'PHP-FPM process crashed unexpectedly' === $exception->getMessage(); + } + + check($crashed, 'FPM OOM did not propagate the expected runtime crash exception'); + cleanupMarkers('/tmp/ymir-security/fpm-fcgi-oom', false); + check($workerPid === (int) file_get_contents('/tmp/ymir-security/fpm-fcgi-oom-ready'), 'OOM did not run on the original warm worker'); + $next = data(request($fpm)); + $warm = data(request($fpm)); + check($next['pid'] !== $workerPid && $next['pid'] === $warm['pid'], 'FPM did not replace the child and reuse its replacement'); + check($masterPid === $process->getPid(), 'Recovery restarted the FPM master instead of replacing the child'); + check([] === $next['post'] && [] === $next['files'] && null === $next['auth_user'], 'Replacement worker inherited request state'); + check(['sentinel' => 'preserved'] === $next['session'], 'OOM recovery changed the persisted session'); + check(str_contains($process->getErrorOutput(), 'Allowed memory size'), 'FPM OOM diagnostic was lost'); + check(1 === preg_match('/child '.$workerPid.' exited with code 1/', $process->getErrorOutput()), 'FPM child did not hard-exit with code 1'); + }, + 'CLI OOM hard-exits without cleanup and ordinary failures stay nonzero' => function (): void { + // PHP 7.2 can reuse PHP_SAPI-specialized FPM bytecode from the shared file cache. + $control = new Process([PHP_BINARY, '-d', 'opcache.enable_cli=0', '-d', 'memory_limit=32M', __DIR__.'/request.php', 'cleanup']); + $control->setTimeout(10); + check(0 === $control->run(), 'CLI cleanup control failed'); + cleanupMarkers('/tmp/ymir-security/cli-cleanup', true); + $oom = new Process([PHP_BINARY, '-d', 'opcache.enable_cli=0', '-d', 'memory_limit=32M', __DIR__.'/request.php', 'oom']); + $oom->setTimeout(10); + $oom->run(); + cleanupMarkers('/tmp/ymir-security/cli-oom', false); + check(1 === $oom->getExitCode(), 'CLI OOM did not hard-exit with code 1'); + check(str_contains($oom->getErrorOutput(), 'Allowed memory size'), 'CLI OOM diagnostic was lost'); + $failure = new Process([PHP_BINARY, '-r', 'exit(7);']); + $failure->setTimeout(10); + check(7 === $failure->run(), 'Ordinary CLI failure exit code changed'); + }, + ]; + + foreach ($tests as $name => $test) { + try { + $test(); + echo ' [OK] '.$name."\n"; + } catch (Throwable $exception) { + $failed = true; + echo ' [FAIL] '.$name.': '.$exception->getMessage()."\n"; + } + } +} finally { + $fpm->stop(); +} + +exit($failed ? 1 : 0); diff --git a/runtime/test-image.sh b/runtime/test-image.sh index dd317b9..f7eef82 100755 --- a/runtime/test-image.sh +++ b/runtime/test-image.sh @@ -10,9 +10,20 @@ if [ -z "$PLATFORM" ]; then PLATFORM="linux/amd64"; fi echo "Testing $IMAGE on $PLATFORM..." FAILED=0 +CID="" +SECURITY_CID="" +cleanup() { + if [ -n "$CID" ]; then docker rm -f "$CID" > /dev/null 2>&1 || true; fi + if [ -n "$SECURITY_CID" ]; then docker rm -f "$SECURITY_CID" > /dev/null 2>&1 || true; fi +} +trap cleanup EXIT +trap 'exit 130' INT +trap 'exit 143' TERM # 1. Size -OPT_SIZE_MB=$(( $(docker run --rm --platform "$PLATFORM" --entrypoint /bin/sh "$IMAGE" -c "du -sk /opt | cut -f1") / 1024 )) +OPT_SIZE_KB=$(docker run --rm --platform "$PLATFORM" --entrypoint /bin/sh "$IMAGE" -c "du -sk /opt | cut -f1") || exit 1 +if ! [[ "$OPT_SIZE_KB" =~ ^[0-9]+$ ]]; then echo " [FAIL] Could not determine image size"; exit 1; fi +OPT_SIZE_MB=$(( OPT_SIZE_KB / 1024 )) if [ "$OPT_SIZE_MB" -gt 250 ]; then echo " [FAIL] Size: ${OPT_SIZE_MB}MB (exceeds 250MB Lambda limit)" @@ -26,7 +37,7 @@ fi # 2. PHP binary & Version echo "--------------------------------------------------------------------------------" -docker run --rm --platform "$PLATFORM" --entrypoint /opt/ymir/bin/php "$IMAGE" -v +docker run --rm --platform "$PLATFORM" --entrypoint /opt/ymir/bin/php "$IMAGE" -v || FAILED=1 echo "--------------------------------------------------------------------------------" # 3. Filesystem layout @@ -73,7 +84,8 @@ if [ -n "$STARTUP_ERRORS" ]; then FAILED=1 fi -PHP_VER=$(docker run --rm --platform "$PLATFORM" -e LD_LIBRARY_PATH="$LAMBDA_LD_PATH" --entrypoint /opt/ymir/bin/php "$IMAGE" -r "echo PHP_VERSION_ID;" 2>/dev/null) +PHP_VER=$(docker run --rm --platform "$PLATFORM" -e LD_LIBRARY_PATH="$LAMBDA_LD_PATH" --entrypoint /opt/ymir/bin/php "$IMAGE" -r "echo PHP_VERSION_ID;" 2>/dev/null) || exit 1 +if ! [[ "$PHP_VER" =~ ^[0-9]+$ ]]; then echo " [FAIL] Could not determine PHP version"; exit 1; fi REQUIRED=("apcu" "igbinary" "zstd" "imagick" "intl" "pdo_mysql" "pdo_pgsql" "pgsql") if [ -n "$PHP_VER" ] && [ "$PHP_VER" -ge 70400 ]; then @@ -171,23 +183,41 @@ FPM_BIN="/opt/ymir/bin/php-fpm" FPM_CONF="/opt/ymir/etc/php-fpm.d/php-fpm.conf" if docker run --rm --platform "$PLATFORM" --entrypoint $FPM_BIN "$IMAGE" -t --fpm-config $FPM_CONF --allow-to-run-as-root; then - CID=$(docker run -d --platform "$PLATFORM" --entrypoint /bin/sh "$IMAGE" -c "mkdir -p /tmp/.ymir && exec $FPM_BIN -F --fpm-config $FPM_CONF --allow-to-run-as-root") + CID=$(docker run -d --platform "$PLATFORM" --entrypoint /bin/sh "$IMAGE" -c "mkdir -p /tmp/.ymir && exec $FPM_BIN -F --fpm-config $FPM_CONF --allow-to-run-as-root") || exit 1 sleep 2 - if docker ps -q --no-trunc | grep -q "$CID"; then + if [ "$(docker inspect --format '{{.State.Running}}' "$CID")" = "true" ]; then echo " [OK] PHP-FPM started" - docker stop "$CID" > /dev/null - docker rm "$CID" > /dev/null + docker stop "$CID" > /dev/null || exit 1 + docker rm "$CID" > /dev/null || exit 1 else echo " [FAIL] PHP-FPM failed to start" docker logs "$CID" - docker rm "$CID" > /dev/null + docker rm "$CID" > /dev/null || exit 1 FAILED=1 fi + CID="" else echo " [FAIL] PHP-FPM configuration test failed" FAILED=1 fi +# 10. Focused EOL mitigation regressions (supported branches have different OOM semantics). +if [ "$PHP_VER" -ge 70200 ] && [ "$PHP_VER" -lt 80200 ]; then + SECURITY_DIR="$(cd "$(dirname "$0")/security" && pwd)" || exit 1 + SECURITY_CID=$(docker create --platform "$PLATFORM" --network none --memory 256m --pids-limit 64 \ + --mount "type=bind,source=$SECURITY_DIR,target=/security,readonly" \ + -e LD_LIBRARY_PATH="$LAMBDA_LD_PATH" --entrypoint /usr/bin/timeout "$IMAGE" \ + 90 /opt/ymir/bin/php /security/verify.php) || exit 1 + docker start --attach "$SECURITY_CID" || exit 1 + SECURITY_STATUS=$(docker wait "$SECURITY_CID") || exit 1 + if [ "$SECURITY_STATUS" != "0" ]; then + echo " [FAIL] Legacy security regressions (container exit $SECURITY_STATUS)" + FAILED=1 + fi + docker rm "$SECURITY_CID" > /dev/null || exit 1 + SECURITY_CID="" +fi + if [ $FAILED -eq 1 ]; then echo "Verification FAILED!" exit 1 From d90b7fd7057b62950078d3555e8ef65035f4e8ec Mon Sep 17 00:00:00 2001 From: Carl Alexander Date: Thu, 22 Oct 2026 11:40:51 -0400 Subject: [PATCH 2/2] fix: build legacy runtimes from complete vendor sources Replace Ymir-maintained patches with pinned PHP-team snapshots and complete Sury source packages prepared by dpkg-source. Preserve AL2023 execution and Lambda defaults without vendor source edits.\n\nVerify the separately fetched upstream PEAR bootstrap before installation and test native session defaults in final images. --- .dockerignore | 1 - runtime/patches/README.md | 205 --- runtime/patches/SHA256SUMS | 11 - .../patches/php-7.2-7.3-multipart-limit.patch | 51 - runtime/patches/php-7.2-security.patch | 893 ------------- runtime/patches/php-7.2-zstr-max-len.patch | 23 - runtime/patches/php-7.3-security.patch | 912 ------------- runtime/patches/php-7.3-zstr-max-len.patch | 22 - runtime/patches/php-7.4-security.patch | 973 -------------- runtime/patches/php-8.0-security.patch | 941 ------------- runtime/patches/php-8.1-security.patch | 1176 ----------------- runtime/php-72/Dockerfile | 38 +- runtime/php-73/Dockerfile | 38 +- runtime/php-74/Dockerfile | 22 +- runtime/php-80/Dockerfile | 22 +- runtime/php-81/Dockerfile | 22 +- runtime/security/request.php | 1 + runtime/security/verify.php | 6 +- runtime/shared/sury-defaults.ini | 5 + runtime/sources/README.md | 119 ++ .../provenance/sury-keyring.gpg | Bin .../provenance/sury-trixie-InRelease | 0 .../provenance/sury-trixie-Sources.xz | Bin runtime/test-image.sh | 19 +- 24 files changed, 251 insertions(+), 5249 deletions(-) delete mode 100644 runtime/patches/README.md delete mode 100644 runtime/patches/SHA256SUMS delete mode 100644 runtime/patches/php-7.2-7.3-multipart-limit.patch delete mode 100644 runtime/patches/php-7.2-security.patch delete mode 100644 runtime/patches/php-7.2-zstr-max-len.patch delete mode 100644 runtime/patches/php-7.3-security.patch delete mode 100644 runtime/patches/php-7.3-zstr-max-len.patch delete mode 100644 runtime/patches/php-7.4-security.patch delete mode 100644 runtime/patches/php-8.0-security.patch delete mode 100644 runtime/patches/php-8.1-security.patch create mode 100644 runtime/shared/sury-defaults.ini create mode 100644 runtime/sources/README.md rename runtime/{patches => sources}/provenance/sury-keyring.gpg (100%) rename runtime/{patches => sources}/provenance/sury-trixie-InRelease (100%) rename runtime/{patches => sources}/provenance/sury-trixie-Sources.xz (100%) diff --git a/.dockerignore b/.dockerignore index 5e5201b..733a9c4 100644 --- a/.dockerignore +++ b/.dockerignore @@ -4,6 +4,5 @@ !runtime/bootstrap !runtime/runtime.php !runtime/shared -!runtime/patches !src !templates diff --git a/runtime/patches/README.md b/runtime/patches/README.md deleted file mode 100644 index a878007..0000000 --- a/runtime/patches/README.md +++ /dev/null @@ -1,205 +0,0 @@ -# Legacy PHP security backports (YMIR-127) - -Pinned minimal EOL mitigations for CVE-2026-109618 / GHSA-w8hw-w9fx-j79w -and CVE-2026-109619 / GHSA-6wmf-4rv5-p3rp. These do not restore upstream -support or include a distro's other historical security fixes. - -## Inputs and application order - -| Pristine source | Patches, in order | -| --- | --- | -| PHP 7.2.34 | `php-7.2-zstr-max-len.patch`, `php-7.2-security.patch`, `php-7.2-7.3-multipart-limit.patch` | -| PHP 7.3.33 | `php-7.3-zstr-max-len.patch`, `php-7.3-security.patch`, `php-7.2-7.3-multipart-limit.patch` | -| PHP 7.4.33 | `php-7.4-security.patch` (PHP security team) | -| PHP 8.0.30 | `php-8.0-security.patch` (PHP security team) | -| PHP 8.1.34 | `php-8.1-security.patch` (PHP security team) | - -The five security patches and two string-limit prerequisite patches are -byte-for-byte copies of the sources below. -`SHA256SUMS` pins all patch and retained provenance bytes: - -```sh -(cd runtime/patches && shasum -a 256 --check SHA256SUMS) -``` - -The Dockerfiles copy only the applicable patches into the build stage and -apply them after extraction, before `buildconf`. `git` is already installed; -`git apply` does not use fuzzy matching, does not partially accept a patch, -and returns failure for rejected hunks. All three 7.2/7.3 applications are -chained with `&&`, so failure of any patch stops the build. No new package or -network-fetched patch is required. Patches/provenance are not copied into -`/opt` or the exported layer. - -The repository build context must allow `runtime/patches/` through -`.dockerignore`; otherwise these `COPY` instructions deliberately fail. - -### Official PHP security-team patches - -Downloaded unchanged from these immutable commit patch URLs: - -- PHP 7.4: https://github.com/php/php-src/commit/712e60f9edfd03f0960fc4fc3c2c375f42b90aa2.patch -- PHP 8.0: https://github.com/php/php-src/commit/82f8f31b16a035c1b67cc253e79f7cc288f4cc20.patch -- PHP 8.1: https://github.com/php/php-src/commit/1d7dec178a094e6e75b229ce22754045f8c6070a.patch - -These are the exceptional EOL backports linked by PHP's October 21, 2026 -security announcement: https://www.php.net/archive/2026.php. -Commit/patch identity was checked over HTTPS, not by a Git commit signature. - -### Sury PHP 7.2/7.3 patches - -Use source patches, not Debian binaries or the entire distro patch series. - -- PHP 7.2 package `7.2.34-66+0~20261021.122+debian13~1.gbpe0bcd4`: - - Archive: https://packages.sury.org/php/pool/main/p/php7.2/php7.2_7.2.34-66%2B0~20261021.122%2Bdebian13~1.gbpe0bcd4.debian.tar.xz - - Archive SHA-256: `4a5a49d808a4d0cd4d32709fbf471519e8c04d81fbc8f237baae073a87454ee9` - - Security member: `debian/patches/0159-Avoid-state-corruption-via-bailout.patch` - - Prerequisite member: `debian/patches/0135-backport-ZSTR_MAX_LEN.patch` - - Adjacent `.dsc` SHA-256: `a06c4b5deeeed7ac81be430c95b74a9f456d21e19ca8d1aae8a2f319d4b1dcfe` -- PHP 7.3 package `7.3.33-35+0~20261021.144+debian13~1.gbpecf76f`: - - Archive: https://packages.sury.org/php/pool/main/p/php7.3/php7.3_7.3.33-35%2B0~20261021.144%2Bdebian13~1.gbpecf76f.debian.tar.xz - - Archive SHA-256: `0c65625f2cbd18749891f7a0bba653c7eabe5864155036cac9407508560eb983` - - Security member: `debian/patches/0139-Avoid-state-corruption-via-bailout.patch` - - Prerequisite member: `debian/patches/0107-backport-ZSTR_MAX_LEN.patch` - - Adjacent `.dsc` SHA-256: `c22d4541d5264ec53918b7d9b70b74121cdfeef1c6974b9fe4e9ad552b310575` - -All four patches are listed in their archive's `debian/patches/series`. - -#### Verified signature chain - -Verified October 22, 2026 using GnuPG, SHA-256, and archive member comparison: - -1. `provenance/sury-keyring.gpg` came from https://packages.sury.org/php/apt.gpg. - Primary key fingerprint: `15058500A0235D97F5D10063B188E2B695BD4743` - (`DEB.SURY.ORG Automatic Signing Key `). -2. `provenance/sury-trixie-InRelease` came from - https://packages.sury.org/php/dists/trixie/InRelease, dated - **2026-10-22 12:01:18 UTC**. `gpgv` returned a good signature and - `VALIDSIG` for that primary fingerprint. -3. Its SHA-256 entry authenticates `provenance/sury-trixie-Sources.xz`, from - https://packages.sury.org/php/dists/trixie/main/source/Sources.xz. -4. The `php7.2` and `php7.3` records authenticate the exact archive and `.dsc` - hashes above. Both archives also match their `.dsc` SHA-256 entries, and - their extracted security/prerequisite patch bytes match `SHA256SUMS`. - -The `.dsc` files are **unsigned**, not independently OpenPGP-signed. The -verified signature is on `InRelease`, covering them through the source -index. The trust anchor is Sury's HTTPS-distributed key, not an independently -established personal/web-of-trust identity. Retained index/signature bytes -are historical provenance, not a current APT freshness check. - -Replay the signature check (from the repository root): - -```sh -gpgv --keyring "$PWD/runtime/patches/provenance/sury-keyring.gpg" \ - runtime/patches/provenance/sury-trixie-InRelease -``` - -### Pristine PHP sources - -Archives are `https://www.php.net/distributions/php-.tar.gz`. -SHA-256 was rechecked against the corresponding `source` entry at -`https://www.php.net/releases/index.php?json&version=`: - -| Version | Archive SHA-256 | -| --- | --- | -| 7.2.34 | `8b2777c741e83f188d3ca6d8e98ece7264acafee86787298fae57e05d0dddc78` | -| 7.3.33 | `9a369c32c6f52036b0a890f290327f148a1904ee66aa56e2c9a7546da6525ec8` | -| 7.4.33 | `5a2337996f07c8a097e03d46263b5c98d2c8e355227756351421003bea8f463e` | -| 8.0.30 | `449d2048fcb20a314d8c218097c6d1047a9f1c5bb72aa54d5d3eba0a27a4c80c` | -| 8.1.34 | `3c5b060ec8e0d5dd1d8237823f3161cc8bc5342aab3c46893eba9857759c4bfa` | - -## The string-limit prerequisite - -The Sury security patches use `ZSTR_MAX_LEN`, also absent from pristine -7.2.34 and 7.3.33. A minimal AL2023 arm64 build of 7.2 initially failed in -`Zend/zend_vm_execute.h` with `ZSTR_MAX_LEN undeclared`; clean patch checks -did not expose this prerequisite. - -The two `php-7.x-zstr-max-len.patch` files add only `ZSTR_MAX_OVERHEAD` and -`ZSTR_MAX_LEN` (plus a blank line) to `Zend/zend_string.h`. The definitions -match pristine PHP 7.4.33 exactly and account for header/alignment overhead -before the new concatenation overflow checks. They are unchanged Sury -archive members from the same authenticated packages, not a wholesale -distro patch series. - -## The pristine-source multipart adaptation - -Sury's headers say `max_multipart_body_parts` was omitted because the distro -already had it. Neither pristine PHP 7.2.34 nor 7.3.33 has it. Applying only -the Sury patch therefore leaves a real hardening gap despite clean hunks. - -`php-7.2-7.3-multipart-limit.patch` restores **only the four omitted hunks** -from official PHP 7.4 commit `712e60f9edfd03f0960fc4fc3c2c375f42b90aa2`. -The hunk bytes, including context, are unchanged; only the patch envelope -is new. Both exact older sources accept them without fuzz after Sury's -patch. Apart from the two string-limit definitions above, no other distro -prerequisites or historical fixes are imported. - -- Register `max_multipart_body_parts`, default `-1`, system/per-directory. -- A negative setting derives the limit from `max_input_vars + max_file_uploads`. -- Count each part with Content-Disposition before parameter/body allocation. -- Warn and use the existing `fileupload_done` cleanup when exceeding the - limit; zero permits no such parts. Earlier accepted parts remain available. - -Review checked those registration, initialization, enforcement, and cleanup -sites against the official 7.4 implementation, not just patch applicability. - -## Verification and release gates - -All five checksum-verified source archives passed, in the order above: - -```sh -git apply --check /absolute/path/to/patch -patch --dry-run --batch --fuzz=0 -p1 -i /absolute/path/to/patch -git apply /absolute/path/to/patch -git apply --reverse --check /absolute/path/to/patch -``` - -Source assertions also checked the four adaptation hunks against official -7.4 bytes, proved the limit absent before/present after on 7.2/7.3, checked -its enforcement before parameter allocation, and checked allocator hard-exit -and session-progress disablement on all five versions, plus the required -string-limit definitions. Applicability and -source inspection alone are not proof of exploit prevention or a bootable -Lambda runtime. Each security patch was also tested with an intentionally -corrupted allocator hunk: `git apply` exited 1 without partially modifying -any source file. A scratch Docker build confirmed the pinned patches are -available through the repository build context. - -Minimal AL2023 **linux/arm64** builds of PHP 7.2.34 and 7.3.33 passed -`buildconf --force`, configuration, and `make -j2`, producing CLI, CGI, and -FPM binaries. Configuration was `CFLAGS=-O1 ./configure --disable-all ---enable-cli --enable-cgi --enable-fpm --enable-session --enable-json ---without-pear`. The repository's `runtime/security/verify.php` also passed -against both minimal builds: normal/nested uploads, upload-progress -disablement, explicit/derived multipart limits, warm-worker state reset, -FPM OOM/child replacement/warm recovery, and CLI OOM/failure exit codes. -These used the runtime's FastCGI/process wrappers, but are not full Ymir -image or extension builds. - -Before release, require both-architecture builds and -`runtime/test-image.sh ` for all five versions, including -upload/nested-form behavior, multipart boundaries, OOM child replacement and -next-request health, session upload-progress disablement, and CLI/queue -failure behavior. The minimal source checks do not validate extensions, -PHP-FPM lifecycle, complete images, layer exports, or earlier/future CVEs. - -### Customer impact and rollback - -- **OOM exits the process immediately with status 1**, bypassing normal PHP - shutdown functions/destructors. An invocation may fail after side effects; - do not add automatic application retries as part of this patch. -- **PHP session upload-progress tracking is disabled unconditionally**, even - if its INI setting is enabled. Ordinary uploads remain supported. -- Multipart limits and ignored duplicate/unused MIME headers can change - malformed or unusually large multipart requests. -- Existing Lambda deployments are not patched retroactively. After separately - authorized publishing/catalog synchronization, zip deployments need a new - deploy; container deployments need patched-base rebuilds and redeployment - (including digest updates where pinned). -- Preserve prior artifacts for recovery. Reverting these changes or deploying - an old image/layer restores the vulnerabilities; prefer a forward fix and - explicitly communicate renewed exposure if rollback is unavoidable. - -No publishing, tags, catalogs, layer names, image aliases, bootstrap paths, -or PHP versions are changed by these source backports. diff --git a/runtime/patches/SHA256SUMS b/runtime/patches/SHA256SUMS deleted file mode 100644 index d441d91..0000000 --- a/runtime/patches/SHA256SUMS +++ /dev/null @@ -1,11 +0,0 @@ -3aa3c16bf76aa929c2140b8ef2632682194fecc4fbd549a08e4980238ea30e34 php-7.2-7.3-multipart-limit.patch -35f4820ab80594899db860be6f6d695657509d6186a830fefd5f442bc2bd0330 php-7.2-security.patch -b4da10ce4bb9aaf57dc3de71f21d200a5a331aec7c34b8c7b946b1db3b9c7e1f php-7.2-zstr-max-len.patch -38b59430a69a7d61919f8875c5d2fa6ff8d4dfaa9277fefc3098be41371af3f0 php-7.3-security.patch -0a9e65e27c04e17b7fb876b639ef769f707ff403d9f2e51330d22fb2047586a1 php-7.3-zstr-max-len.patch -5fe57ca6ee96d59b36c6e0ca842843c50884f177bef1e85234cf669b577f5e48 php-7.4-security.patch -534478c973cef6f493605b7af907f639a364912ee92c24598ddae44c3bc72d1c php-8.0-security.patch -c85ad0fddcbff7f2318617eeaa54d271135463b5bf70a01228447e3ed78de96e php-8.1-security.patch -b486fd5488185c4c46467960fa69c53d5085fec492cf76b9eaf3db33561c9d7c provenance/sury-keyring.gpg -3cdc3b580e315a6c214f9723af0c4663f7498c48c09eedfd325681ff801a3f63 provenance/sury-trixie-InRelease -bce36b31bf6b87c32bc8a8f28112502f78e26bf4f2c247b5a4a2d07e20d34c09 provenance/sury-trixie-Sources.xz diff --git a/runtime/patches/php-7.2-7.3-multipart-limit.patch b/runtime/patches/php-7.2-7.3-multipart-limit.patch deleted file mode 100644 index 34e89f6..0000000 --- a/runtime/patches/php-7.2-7.3-multipart-limit.patch +++ /dev/null @@ -1,51 +0,0 @@ -Subject: Restore the multipart limit omitted by the Sury 7.2/7.3 backports - -Apply after the matching Sury security patch to pristine upstream sources. -These four hunks are unchanged from PHP security-team commit -712e60f9edfd03f0960fc4fc3c2c375f42b90aa2; only the patch headers differ. -The distro already had this limit, but pristine PHP 7.2.34/7.3.33 did not. - ---- a/main/main.c -+++ b/main/main.c -@@ -836,6 +836,7 @@ PHP_INI_BEGIN() - PHP_INI_ENTRY("disable_functions", "", PHP_INI_SYSTEM, NULL) - PHP_INI_ENTRY("disable_classes", "", PHP_INI_SYSTEM, NULL) - PHP_INI_ENTRY("max_file_uploads", "20", PHP_INI_SYSTEM|PHP_INI_PERDIR, NULL) -+ PHP_INI_ENTRY("max_multipart_body_parts", "-1", PHP_INI_SYSTEM|PHP_INI_PERDIR, NULL) - - STD_PHP_INI_BOOLEAN("allow_url_fopen", "1", PHP_INI_SYSTEM, OnUpdateBool, allow_url_fopen, php_core_globals, core_globals) - STD_PHP_INI_BOOLEAN("allow_url_include", "0", PHP_INI_SYSTEM, OnUpdateBool, allow_url_include, php_core_globals, core_globals) ---- a/main/rfc1867.c -+++ b/main/rfc1867.c -@@ -694,6 +708,7 @@ SAPI_API SAPI_POST_HANDLER_FUNC(rfc1867_post_handler) /* {{{ */ - void *event_extra_data = NULL; - unsigned int llen = 0; - int upload_cnt = INI_INT("max_file_uploads"); -+ int body_parts_cnt = INI_INT("max_multipart_body_parts"); - const zend_encoding *internal_encoding = zend_multibyte_get_internal_encoding(); - php_rfc1867_getword_t getword; - php_rfc1867_getword_conf_t getword_conf; -@@ -715,6 +730,11 @@ SAPI_API SAPI_POST_HANDLER_FUNC(rfc1867_post_handler) /* {{{ */ - return; - } - -+ if (body_parts_cnt < 0) { -+ body_parts_cnt = PG(max_input_vars) + upload_cnt; -+ } -+ int body_parts_limit = body_parts_cnt; -+ - /* Get the boundary */ - boundary = strstr(content_type_dup, "boundary"); - if (!boundary) { -@@ -799,6 +819,11 @@ SAPI_API SAPI_POST_HANDLER_FUNC(rfc1867_post_handler) /* {{{ */ - char *pair = NULL; - int end = 0; - -+ if (--body_parts_cnt < 0) { -+ php_error_docref(NULL, E_WARNING, "Multipart body parts limit exceeded %d. To increase the limit change max_multipart_body_parts in php.ini.", body_parts_limit); -+ goto fileupload_done; -+ } -+ - while (isspace(*cd)) { - ++cd; - } diff --git a/runtime/patches/php-7.2-security.patch b/runtime/patches/php-7.2-security.patch deleted file mode 100644 index 7339fc5..0000000 --- a/runtime/patches/php-7.2-security.patch +++ /dev/null @@ -1,893 +0,0 @@ -From: Arnaud Le Blanc -Date: Sun, 18 Oct 2026 20:09:54 +0200 -Subject: Avoid state corruption via bailout - -Minimal mitigation for EOL version. - -Fix GHSA-w8hw-w9fx-j79w (CVE-2026-109618) -Fix GHSA-6wmf-4rv5-p3rp (CVE-2026-109619) - -Backported from the PHP 7.4 version: -- shutdown_executor() frees the object store before the error handlers, - so the fast shutdown resets are done just before - zend_objects_store_free_object_storage(). -- "|| 1" instead of "|| true" in the session upload progress callback - (no stdbool.h). -- The max_multipart_body_parts hunk of the 7.4 patch is left out, the - code is already there. -- array_init_singleton() is implemented in zend_API.c, there is no - zend_new_array(); HT_HASH_RESET() uses memset(), so the SSE2 change is - not needed. - -Co-authored-by: Ilija Tovilo ---- - Zend/zend_API.c | 8 +++ - Zend/zend_API.h | 2 + - Zend/zend_alloc.c | 68 +++++++++++++++++-------- - Zend/zend_alloc.h | 2 + - Zend/zend_execute_API.c | 15 ++++++ - Zend/zend_hash.c | 6 +-- - Zend/zend_llist.c | 2 + - Zend/zend_multiply.h | 4 +- - Zend/zend_strtod.c | 4 +- - Zend/zend_vm_def.h | 12 +++++ - Zend/zend_vm_execute.h | 108 ++++++++++++++++++++++++++++++++++++++++ - ext/session/session.c | 2 +- - main/SAPI.c | 5 ++ - main/main.c | 5 ++ - main/php_variables.c | 8 +-- - main/rfc1867.c | 29 ++++++++--- - 16 files changed, 240 insertions(+), 40 deletions(-) - -diff --git a/Zend/zend_API.c b/Zend/zend_API.c -index 604450e9..738266cf 100644 ---- a/Zend/zend_API.c -+++ b/Zend/zend_API.c -@@ -1093,6 +1093,14 @@ ZEND_API int _array_init(zval *arg, uint32_t size ZEND_FILE_LINE_DC) /* {{{ */ - } - /* }}} */ - -+ZEND_API int _array_init_singleton(zval *arg ZEND_FILE_LINE_DC) /* {{{ */ -+{ -+ _array_init(arg, 0 ZEND_FILE_LINE_RELAY_CC); -+ Z_ARRVAL_P(arg)->nTableSize = 1; -+ return SUCCESS; -+} -+/* }}} */ -+ - /* This function should be called after the constructor has been called - * because it may call __set from the uninitialized object otherwise. */ - ZEND_API void zend_merge_properties(zval *obj, HashTable *properties) /* {{{ */ -diff --git a/Zend/zend_API.h b/Zend/zend_API.h -index 38407703..763c64ab 100644 ---- a/Zend/zend_API.h -+++ b/Zend/zend_API.h -@@ -392,10 +392,12 @@ ZEND_API char *zend_get_type_by_const(int type); - - #define array_init(arg) _array_init((arg), 0 ZEND_FILE_LINE_CC) - #define array_init_size(arg, size) _array_init((arg), (size) ZEND_FILE_LINE_CC) -+#define array_init_singleton(arg) _array_init_singleton((arg) ZEND_FILE_LINE_CC) - #define object_init(arg) _object_init((arg) ZEND_FILE_LINE_CC) - #define object_init_ex(arg, ce) _object_init_ex((arg), (ce) ZEND_FILE_LINE_CC) - #define object_and_properties_init(arg, ce, properties) _object_and_properties_init((arg), (ce), (properties) ZEND_FILE_LINE_CC) - ZEND_API int _array_init(zval *arg, uint32_t size ZEND_FILE_LINE_DC); -+ZEND_API int _array_init_singleton(zval *arg ZEND_FILE_LINE_DC); - ZEND_API int _object_init(zval *arg ZEND_FILE_LINE_DC); - ZEND_API int _object_init_ex(zval *arg, zend_class_entry *ce ZEND_FILE_LINE_DC); - ZEND_API int _object_and_properties_init(zval *arg, zend_class_entry *ce, HashTable *properties ZEND_FILE_LINE_DC); -diff --git a/Zend/zend_alloc.c b/Zend/zend_alloc.c -index f4a61795..4b914251 100644 ---- a/Zend/zend_alloc.c -+++ b/Zend/zend_alloc.c -@@ -59,6 +59,7 @@ - #include "zend_operators.h" - #include "zend_multiply.h" - #include "zend_bitset.h" -+#include "zend_execute.h" - - #ifdef HAVE_SIGNAL_H - # include -@@ -360,7 +361,42 @@ static ZEND_COLD ZEND_NORETURN void zend_mm_panic(const char *message) - #if ZEND_DEBUG && defined(HAVE_KILL) && defined(HAVE_GETPID) - kill(getpid(), SIGSEGV); - #endif -- exit(1); -+ _exit(1); -+} -+ -+ZEND_API ZEND_COLD ZEND_NORETURN void zend_mm_safe_error_ex(const char *format, ...) -+{ -+ zend_string *script_filename = NULL; -+ uint32_t script_lineno = 0; -+ -+ if (zend_is_executing()) { -+ script_filename = zend_get_executed_filename_ex(); -+ script_lineno = zend_get_executed_lineno(); -+ } else if (zend_is_compiling()) { -+ script_filename = zend_get_compiled_filename(); -+ script_lineno = zend_get_compiled_lineno(); -+ } -+ -+ va_list args; -+ va_start(args, format); -+ -+ char buf[1024]; -+ vsnprintf(buf, sizeof(buf), format, args); -+ -+ va_end(args); -+ -+ fprintf(stderr, -+ "\nFatal error: %s in %s on line %d\n", -+ buf, -+ script_filename ? ZSTR_VAL(script_filename) : "Unknown", -+ script_lineno); -+ -+ /* See http://support.microsoft.com/kb/190351 */ -+# ifdef ZEND_WIN32 -+ fflush(stderr); -+# endif -+ -+ _exit(1); - } - - static ZEND_COLD ZEND_NORETURN void zend_mm_safe_error(zend_mm_heap *heap, -@@ -372,22 +408,14 @@ static ZEND_COLD ZEND_NORETURN void zend_mm_safe_error(zend_mm_heap *heap, - #endif - size_t size) - { -+ (void) heap; - -- heap->overflow = 1; -- zend_try { -- zend_error_noreturn(E_ERROR, -- format, -- limit, -+ zend_mm_safe_error_ex(format, limit, - #if ZEND_DEBUG -- filename, -- lineno, -+ filename, -+ lineno, - #endif -- size); -- } zend_catch { -- } zend_end_try(); -- heap->overflow = 0; -- zend_bailout(); -- exit(1); -+ size); - } - - #ifdef _WIN32 -@@ -1338,7 +1366,7 @@ static zend_always_inline void *zend_mm_alloc_heap(zend_mm_heap *heap, size_t si - size = MAX(size, 1); - size = ZEND_MM_ALIGNED_SIZE(size) + ZEND_MM_ALIGNED_SIZE(sizeof(zend_mm_debug_info)); - if (UNEXPECTED(size < real_size)) { -- zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%zu + %zu)", ZEND_MM_ALIGNED_SIZE(real_size), ZEND_MM_ALIGNED_SIZE(sizeof(zend_mm_debug_info))); -+ zend_mm_safe_error_ex("Possible integer overflow in memory allocation (%zu + %zu)", ZEND_MM_ALIGNED_SIZE(real_size), ZEND_MM_ALIGNED_SIZE(sizeof(zend_mm_debug_info))); - return NULL; - } - #endif -@@ -1731,7 +1759,7 @@ static void *zend_mm_alloc_huge(zend_mm_heap *heap, size_t size ZEND_FILE_LINE_D - void *ptr; - - if (UNEXPECTED(new_size < size)) { -- zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%zu + %zu)", size, alignment); -+ zend_mm_safe_error_ex("Possible integer overflow in memory allocation (%zu + %zu)", size, alignment); - } - - #if ZEND_MM_LIMIT -@@ -2527,7 +2555,7 @@ ZEND_API char* ZEND_FASTCALL _estrdup(const char *s ZEND_FILE_LINE_DC ZEND_FILE_ - - length = strlen(s); - if (UNEXPECTED(length + 1 == 0)) { -- zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (1 * %zu + 1)", length); -+ zend_mm_safe_error_ex("Possible integer overflow in memory allocation (1 * %zu + 1)", length); - } - p = (char *) _emalloc(length + 1 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC); - memcpy(p, s, length+1); -@@ -2539,7 +2567,7 @@ ZEND_API char* ZEND_FASTCALL _estrndup(const char *s, size_t length ZEND_FILE_LI - char *p; - - if (UNEXPECTED(length + 1 == 0)) { -- zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (1 * %zu + 1)", length); -+ zend_mm_safe_error_ex("Possible integer overflow in memory allocation (1 * %zu + 1)", length); - } - p = (char *) _emalloc(length + 1 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC); - memcpy(p, s, length); -@@ -2553,7 +2581,7 @@ ZEND_API char* ZEND_FASTCALL zend_strndup(const char *s, size_t length) - char *p; - - if (UNEXPECTED(length + 1 == 0)) { -- zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (1 * %zu + 1)", length); -+ zend_mm_safe_error_ex("Possible integer overflow in memory allocation (1 * %zu + 1)", length); - } - p = (char *) malloc(length + 1); - if (UNEXPECTED(p == NULL)) { -@@ -2827,7 +2855,7 @@ ZEND_API zend_mm_heap *zend_mm_startup_ex(const zend_mm_handlers *handlers, void - static ZEND_COLD ZEND_NORETURN void zend_out_of_memory(void) - { - fprintf(stderr, "Out of memory\n"); -- exit(1); -+ _exit(1); - } - - ZEND_API void * __zend_malloc(size_t len) -diff --git a/Zend/zend_alloc.h b/Zend/zend_alloc.h -index e3ab221e..334004c5 100644 ---- a/Zend/zend_alloc.h -+++ b/Zend/zend_alloc.h -@@ -399,6 +399,8 @@ static void apc_init_heap(void) - - */ - -+ZEND_API ZEND_COLD ZEND_NORETURN void zend_mm_safe_error_ex(const char *format, ...); -+ - END_EXTERN_C() - - #endif -diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c -index 9f10843b..99d4ffa6 100644 ---- a/Zend/zend_execute_API.c -+++ b/Zend/zend_execute_API.c -@@ -263,8 +263,21 @@ void shutdown_executor(void) /* {{{ */ - zend_close_rsrc_list(&EG(regular_list)); - } zend_end_try(); - -+ if (fast_shutdown) { -+ /* may be used by zend_error before init_executor */ -+ ZVAL_UNDEF(&EG(user_error_handler)); -+ ZVAL_UNDEF(&EG(user_exception_handler)); -+ memset(&EG(user_error_handlers_error_reporting), 0, sizeof(EG(user_error_handlers_error_reporting))); -+ memset(&EG(user_error_handlers), 0, sizeof(EG(user_error_handlers))); -+ memset(&EG(user_exception_handlers), 0, sizeof(EG(user_exception_handlers))); -+ } -+ - zend_objects_store_free_object_storage(&EG(objects_store), fast_shutdown); - -+ /* may be used by zend_error before init_executor */ -+ EG(error_handling) = EH_NORMAL; -+ EG(exception) = NULL; -+ - /* All resources and objects are destroyed. */ - /* No PHP callback functions may be called after this point. */ - EG(active) = 0; -@@ -299,6 +312,8 @@ void shutdown_executor(void) /* {{{ */ - } ZEND_HASH_FOREACH_END_DEL(); - - zend_cleanup_internal_classes(); -+ EG(objects_store).object_buckets = NULL; -+ EG(objects_store).top = 1; - } else { - zend_hash_graceful_reverse_destroy(&EG(symbol_table)); - -diff --git a/Zend/zend_hash.c b/Zend/zend_hash.c -index f5fba679..d6c022a2 100644 ---- a/Zend/zend_hash.c -+++ b/Zend/zend_hash.c -@@ -103,7 +103,7 @@ static zend_always_inline uint32_t zend_hash_check_size(uint32_t nSize) - if (nSize < HT_MIN_SIZE) { - nSize = HT_MIN_SIZE; - } else if (UNEXPECTED(nSize >= HT_MAX_SIZE)) { -- zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%u * %zu + %zu)", nSize, sizeof(Bucket), sizeof(Bucket)); -+ zend_mm_safe_error_ex("Possible integer overflow in memory allocation (%u * %zu + %zu)", nSize, sizeof(Bucket), sizeof(Bucket)); - } - - #if defined(ZEND_WIN32) -@@ -189,7 +189,7 @@ static void ZEND_FASTCALL zend_hash_packed_grow(HashTable *ht) - { - HT_ASSERT_RC1(ht); - if (ht->nTableSize >= HT_MAX_SIZE) { -- zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%u * %zu + %zu)", ht->nTableSize * 2, sizeof(Bucket), sizeof(Bucket)); -+ zend_mm_safe_error_ex("Possible integer overflow in memory allocation (%u * %zu + %zu)", ht->nTableSize * 2, sizeof(Bucket), sizeof(Bucket)); - } - ht->nTableSize += ht->nTableSize; - HT_SET_DATA_ADDR(ht, perealloc2(HT_GET_DATA_ADDR(ht), HT_SIZE(ht), HT_USED_SIZE(ht), ht->u.flags & HASH_FLAG_PERSISTENT)); -@@ -865,7 +865,7 @@ static void ZEND_FASTCALL zend_hash_do_resize(HashTable *ht) - pefree(old_data, ht->u.flags & HASH_FLAG_PERSISTENT); - zend_hash_rehash(ht); - } else { -- zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%u * %zu + %zu)", ht->nTableSize * 2, sizeof(Bucket) + sizeof(uint32_t), sizeof(Bucket)); -+ zend_mm_safe_error_ex("Possible integer overflow in memory allocation (%u * %zu + %zu)", ht->nTableSize * 2, sizeof(Bucket) + sizeof(uint32_t), sizeof(Bucket)); - } - } - -diff --git a/Zend/zend_llist.c b/Zend/zend_llist.c -index de93f295..4b0509cb 100644 ---- a/Zend/zend_llist.c -+++ b/Zend/zend_llist.c -@@ -114,6 +114,8 @@ ZEND_API void zend_llist_destroy(zend_llist *l) - current = next; - } - -+ l->head = NULL; -+ l->tail = NULL; - l->count = 0; - } - -diff --git a/Zend/zend_multiply.h b/Zend/zend_multiply.h -index 26853a3c..386f9353 100644 ---- a/Zend/zend_multiply.h -+++ b/Zend/zend_multiply.h -@@ -309,7 +309,7 @@ static zend_always_inline size_t zend_safe_address_guarded(size_t nmemb, size_t - size_t ret = zend_safe_address(nmemb, size, offset, &overflow); - - if (UNEXPECTED(overflow)) { -- zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%zu * %zu + %zu)", nmemb, size, offset); -+ zend_mm_safe_error_ex("Possible integer overflow in memory allocation (%zu * %zu + %zu)", nmemb, size, offset); - return 0; - } - return ret; -@@ -322,7 +322,7 @@ static zend_always_inline size_t zend_safe_addmult(size_t nmemb, size_t size, si - size_t ret = zend_safe_address(nmemb, size, offset, &overflow); - - if (UNEXPECTED(overflow)) { -- zend_error_noreturn(E_ERROR, "Possible integer overflow in %s (%zu * %zu + %zu)", message, nmemb, size, offset); -+ zend_mm_safe_error_ex("Possible integer overflow in %s (%zu * %zu + %zu)", message, nmemb, size, offset); - return 0; - } - return ret; -diff --git a/Zend/zend_strtod.c b/Zend/zend_strtod.c -index 3aa99f8d..01c1779d 100644 ---- a/Zend/zend_strtod.c -+++ b/Zend/zend_strtod.c -@@ -600,7 +600,7 @@ Balloc - rv = (Bigint *)MALLOC(sizeof(Bigint) + (x-1)*sizeof(ULong)); - if (!rv) { - FREE_DTOA_LOCK(0); -- zend_error_noreturn(E_ERROR, "Balloc() failed to allocate memory"); -+ zend_mm_safe_error_ex("Balloc() failed to allocate memory"); - } - #else - len = (sizeof(Bigint) + (x-1)*sizeof(ULong) + sizeof(double) - 1) -@@ -613,7 +613,7 @@ Balloc - rv = (Bigint*)MALLOC(len*sizeof(double)); - if (!rv) { - FREE_DTOA_LOCK(0); -- zend_error_noreturn(E_ERROR, "Balloc() failed to allocate memory"); -+ zend_mm_safe_error_ex("Balloc() failed to allocate memory"); - } - #endif - rv->k = k; -diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h -index ed84d17b..ebdb2fdc 100644 ---- a/Zend/zend_vm_def.h -+++ b/Zend/zend_vm_def.h -@@ -316,11 +316,17 @@ ZEND_VM_HANDLER(8, ZEND_CONCAT, CONST|TMPVAR|CV, CONST|TMPVAR|CV) - !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { - size_t len = ZSTR_LEN(op1_str); - -+ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); - ZVAL_NEW_STR(EX_VAR(opline->result.var), str); - break; - } else { -+ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); - memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -2716,11 +2722,17 @@ ZEND_VM_HANDLER(53, ZEND_FAST_CONCAT, CONST|TMPVAR|CV, CONST|TMPVAR|CV) - !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { - size_t len = ZSTR_LEN(op1_str); - -+ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); - ZVAL_NEW_STR(EX_VAR(opline->result.var), str); - break; - } else { -+ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); - memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h -index 3f975dec..b0170aff 100644 ---- a/Zend/zend_vm_execute.h -+++ b/Zend/zend_vm_execute.h -@@ -4406,11 +4406,17 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_CONST_CONST_HANDLE - !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { - size_t len = ZSTR_LEN(op1_str); - -+ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); - ZVAL_NEW_STR(EX_VAR(opline->result.var), str); - break; - } else { -+ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); - memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -5202,11 +5208,17 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CONST_CONST_H - !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { - size_t len = ZSTR_LEN(op1_str); - -+ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); - ZVAL_NEW_STR(EX_VAR(opline->result.var), str); - break; - } else { -+ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); - memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -8524,11 +8536,17 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_CONST_CV_HANDLER(Z - !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { - size_t len = ZSTR_LEN(op1_str); - -+ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); - ZVAL_NEW_STR(EX_VAR(opline->result.var), str); - break; - } else { -+ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); - memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -9253,11 +9271,17 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CONST_CV_HAND - !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { - size_t len = ZSTR_LEN(op1_str); - -+ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); - ZVAL_NEW_STR(EX_VAR(opline->result.var), str); - break; - } else { -+ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); - memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -10580,11 +10604,17 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_CONST_TMPVAR_HANDL - !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { - size_t len = ZSTR_LEN(op1_str); - -+ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); - ZVAL_NEW_STR(EX_VAR(opline->result.var), str); - break; - } else { -+ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); - memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -11275,11 +11305,17 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CONST_TMPVAR_ - !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { - size_t len = ZSTR_LEN(op1_str); - -+ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); - ZVAL_NEW_STR(EX_VAR(opline->result.var), str); - break; - } else { -+ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); - memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -35136,11 +35172,17 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_CV_CONST_HANDLER(Z - !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { - size_t len = ZSTR_LEN(op1_str); - -+ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); - ZVAL_NEW_STR(EX_VAR(opline->result.var), str); - break; - } else { -+ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); - memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -37690,11 +37732,17 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CV_CONST_HAND - !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { - size_t len = ZSTR_LEN(op1_str); - -+ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); - ZVAL_NEW_STR(EX_VAR(opline->result.var), str); - break; - } else { -+ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); - memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -41657,11 +41705,17 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_CV_CV_HANDLER(ZEND - !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { - size_t len = ZSTR_LEN(op1_str); - -+ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); - ZVAL_NEW_STR(EX_VAR(opline->result.var), str); - break; - } else { -+ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); - memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -44200,11 +44254,17 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CV_CV_HANDLER - !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { - size_t len = ZSTR_LEN(op1_str); - -+ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); - ZVAL_NEW_STR(EX_VAR(opline->result.var), str); - break; - } else { -+ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); - memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -45369,11 +45429,17 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_CV_TMPVAR_HANDLER( - !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { - size_t len = ZSTR_LEN(op1_str); - -+ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); - ZVAL_NEW_STR(EX_VAR(opline->result.var), str); - break; - } else { -+ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); - memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -47770,11 +47836,17 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CV_TMPVAR_HAN - !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { - size_t len = ZSTR_LEN(op1_str); - -+ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); - ZVAL_NEW_STR(EX_VAR(opline->result.var), str); - break; - } else { -+ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); - memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -49343,11 +49415,17 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_TMPVAR_CONST_HANDL - !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { - size_t len = ZSTR_LEN(op1_str); - -+ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); - ZVAL_NEW_STR(EX_VAR(opline->result.var), str); - break; - } else { -+ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); - memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -49957,11 +50035,17 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_TMPVAR_CONST_ - !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { - size_t len = ZSTR_LEN(op1_str); - -+ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); - ZVAL_NEW_STR(EX_VAR(opline->result.var), str); - break; - } else { -+ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); - memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -51749,11 +51833,17 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_TMPVAR_CV_HANDLER( - !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { - size_t len = ZSTR_LEN(op1_str); - -+ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); - ZVAL_NEW_STR(EX_VAR(opline->result.var), str); - break; - } else { -+ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); - memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -52294,11 +52384,17 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_TMPVAR_CV_HAN - !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { - size_t len = ZSTR_LEN(op1_str); - -+ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); - ZVAL_NEW_STR(EX_VAR(opline->result.var), str); - break; - } else { -+ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); - memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -53079,11 +53175,17 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_TMPVAR_TMPVAR_HAND - !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { - size_t len = ZSTR_LEN(op1_str); - -+ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); - ZVAL_NEW_STR(EX_VAR(opline->result.var), str); - break; - } else { -+ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); - memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -53625,11 +53727,17 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_TMPVAR_TMPVAR - !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { - size_t len = ZSTR_LEN(op1_str); - -+ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); - ZVAL_NEW_STR(EX_VAR(opline->result.var), str); - break; - } else { -+ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); - memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -diff --git a/ext/session/session.c b/ext/session/session.c -index 0f0d9bcb..8be81f6d 100644 ---- a/ext/session/session.c -+++ b/ext/session/session.c -@@ -3071,7 +3071,7 @@ static int php_session_rfc1867_callback(unsigned int event, void *event_data, vo - if (php_session_rfc1867_orig_callback) { - retval = php_session_rfc1867_orig_callback(event, event_data, extra); - } -- if (!PS(rfc1867_enabled)) { -+ if (!PS(rfc1867_enabled) || 1) { - return retval; - } - -diff --git a/main/SAPI.c b/main/SAPI.c -index 01383357..17afa0e0 100644 ---- a/main/SAPI.c -+++ b/main/SAPI.c -@@ -515,18 +515,23 @@ SAPI_API void sapi_deactivate(void) - } - if (SG(request_info).auth_user) { - efree(SG(request_info).auth_user); -+ SG(request_info).auth_user = NULL; - } - if (SG(request_info).auth_password) { - efree(SG(request_info).auth_password); -+ SG(request_info).auth_password = NULL; - } - if (SG(request_info).auth_digest) { - efree(SG(request_info).auth_digest); -+ SG(request_info).auth_digest = NULL; - } - if (SG(request_info).content_type_dup) { - efree(SG(request_info).content_type_dup); -+ SG(request_info).content_type_dup = NULL; - } - if (SG(request_info).current_user) { - efree(SG(request_info).current_user); -+ SG(request_info).current_user = NULL; - } - if (sapi_module.deactivate) { - sapi_module.deactivate(); -diff --git a/main/main.c b/main/main.c -index 0cfdb913..92c19e46 100644 ---- a/main/main.c -+++ b/main/main.c -@@ -1895,6 +1895,8 @@ void php_request_shutdown(void *dummy) - - for (i=0; i -Date: Fri, 22 Nov 2024 15:24:16 +0100 -Subject: backport ZSTR_MAX_LEN - -(cherry picked from commit 37056ad634d9c44bac0d6c8e730eafaec1344840) ---- - Zend/zend_string.h | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/Zend/zend_string.h b/Zend/zend_string.h -index 784b88e..5f7a9ea 100644 ---- a/Zend/zend_string.h -+++ b/Zend/zend_string.h -@@ -74,6 +74,9 @@ END_EXTERN_C() - - #define _ZSTR_STRUCT_SIZE(len) (_ZSTR_HEADER_SIZE + len + 1) - -+#define ZSTR_MAX_OVERHEAD (ZEND_MM_ALIGNED_SIZE(_ZSTR_HEADER_SIZE + 1)) -+#define ZSTR_MAX_LEN (SIZE_MAX - ZSTR_MAX_OVERHEAD) -+ - #define ZSTR_ALLOCA_ALLOC(str, _len, use_heap) do { \ - (str) = (zend_string *)do_alloca(ZEND_MM_ALIGNED_SIZE_EX(_ZSTR_STRUCT_SIZE(_len), 8), (use_heap)); \ - GC_REFCOUNT(str) = 1; \ diff --git a/runtime/patches/php-7.3-security.patch b/runtime/patches/php-7.3-security.patch deleted file mode 100644 index 5504293..0000000 --- a/runtime/patches/php-7.3-security.patch +++ /dev/null @@ -1,912 +0,0 @@ -From: Arnaud Le Blanc -Date: Sun, 18 Oct 2026 20:09:54 +0200 -Subject: Avoid state corruption via bailout - -Minimal mitigation for EOL version. - -Fix GHSA-w8hw-w9fx-j79w (CVE-2026-109618) -Fix GHSA-6wmf-4rv5-p3rp (CVE-2026-109619) - -Backported from the PHP 7.4 version: -- shutdown_executor() frees the object store before the error handlers, - so the fast shutdown resets are done just before - zend_objects_store_free_object_storage(). -- "|| 1" instead of "|| true" in the session upload progress callback - (no stdbool.h). -- The max_multipart_body_parts hunk of the 7.4 patch is left out, the - code is already there. - -Co-authored-by: Ilija Tovilo ---- - Zend/zend_API.h | 1 + - Zend/zend_alloc.c | 68 +++++++++++++++++++-------- - Zend/zend_alloc.h | 2 + - Zend/zend_execute_API.c | 15 ++++++ - Zend/zend_hash.c | 13 +++-- - Zend/zend_hash.h | 1 + - Zend/zend_llist.c | 2 + - Zend/zend_multiply.h | 4 +- - Zend/zend_strtod.c | 4 +- - Zend/zend_types.h | 26 +++++----- - Zend/zend_vm_def.h | 12 +++++ - Zend/zend_vm_execute.h | 102 ++++++++++++++++++++++++++++++++++++++++ - ext/session/session.c | 2 +- - main/SAPI.c | 5 ++ - main/main.c | 5 ++ - main/php_variables.c | 8 ++-- - main/rfc1867.c | 29 ++++++++---- - 17 files changed, 248 insertions(+), 51 deletions(-) - -diff --git a/Zend/zend_API.h b/Zend/zend_API.h -index 3c134f44..67942e39 100644 ---- a/Zend/zend_API.h -+++ b/Zend/zend_API.h -@@ -376,6 +376,7 @@ ZEND_API char *zend_get_type_by_const(int type); - - #define array_init(arg) ZVAL_ARR((arg), zend_new_array(0)) - #define array_init_size(arg, size) ZVAL_ARR((arg), zend_new_array(size)) -+#define array_init_singleton(arg) ZVAL_ARR((arg), zend_new_array_singleton()) - ZEND_API int object_init(zval *arg); - ZEND_API int object_init_ex(zval *arg, zend_class_entry *ce); - ZEND_API int object_and_properties_init(zval *arg, zend_class_entry *ce, HashTable *properties); -diff --git a/Zend/zend_alloc.c b/Zend/zend_alloc.c -index 25216898..126aa124 100644 ---- a/Zend/zend_alloc.c -+++ b/Zend/zend_alloc.c -@@ -57,6 +57,7 @@ - #include "zend_operators.h" - #include "zend_multiply.h" - #include "zend_bitset.h" -+#include "zend_execute.h" - - #ifdef HAVE_SIGNAL_H - # include -@@ -358,7 +359,42 @@ static ZEND_COLD ZEND_NORETURN void zend_mm_panic(const char *message) - #if ZEND_DEBUG && defined(HAVE_KILL) && defined(HAVE_GETPID) - kill(getpid(), SIGSEGV); - #endif -- exit(1); -+ _exit(1); -+} -+ -+ZEND_API ZEND_COLD ZEND_NORETURN void zend_mm_safe_error_ex(const char *format, ...) -+{ -+ zend_string *script_filename = NULL; -+ uint32_t script_lineno = 0; -+ -+ if (zend_is_executing()) { -+ script_filename = zend_get_executed_filename_ex(); -+ script_lineno = zend_get_executed_lineno(); -+ } else if (zend_is_compiling()) { -+ script_filename = zend_get_compiled_filename(); -+ script_lineno = zend_get_compiled_lineno(); -+ } -+ -+ va_list args; -+ va_start(args, format); -+ -+ char buf[1024]; -+ vsnprintf(buf, sizeof(buf), format, args); -+ -+ va_end(args); -+ -+ fprintf(stderr, -+ "\nFatal error: %s in %s on line %d\n", -+ buf, -+ script_filename ? ZSTR_VAL(script_filename) : "Unknown", -+ script_lineno); -+ -+ /* See http://support.microsoft.com/kb/190351 */ -+# ifdef ZEND_WIN32 -+ fflush(stderr); -+# endif -+ -+ _exit(1); - } - - static ZEND_COLD ZEND_NORETURN void zend_mm_safe_error(zend_mm_heap *heap, -@@ -370,22 +406,14 @@ static ZEND_COLD ZEND_NORETURN void zend_mm_safe_error(zend_mm_heap *heap, - #endif - size_t size) - { -+ (void) heap; - -- heap->overflow = 1; -- zend_try { -- zend_error_noreturn(E_ERROR, -- format, -- limit, -+ zend_mm_safe_error_ex(format, limit, - #if ZEND_DEBUG -- filename, -- lineno, -+ filename, -+ lineno, - #endif -- size); -- } zend_catch { -- } zend_end_try(); -- heap->overflow = 0; -- zend_bailout(); -- exit(1); -+ size); - } - - #ifdef _WIN32 -@@ -1352,7 +1380,7 @@ static zend_always_inline void *zend_mm_alloc_heap(zend_mm_heap *heap, size_t si - size = MAX(size, 1); - size = ZEND_MM_ALIGNED_SIZE(size) + ZEND_MM_ALIGNED_SIZE(sizeof(zend_mm_debug_info)); - if (UNEXPECTED(size < real_size)) { -- zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%zu + %zu)", ZEND_MM_ALIGNED_SIZE(real_size), ZEND_MM_ALIGNED_SIZE(sizeof(zend_mm_debug_info))); -+ zend_mm_safe_error_ex("Possible integer overflow in memory allocation (%zu + %zu)", ZEND_MM_ALIGNED_SIZE(real_size), ZEND_MM_ALIGNED_SIZE(sizeof(zend_mm_debug_info))); - return NULL; - } - #endif -@@ -1800,7 +1828,7 @@ static void *zend_mm_alloc_huge(zend_mm_heap *heap, size_t size ZEND_FILE_LINE_D - void *ptr; - - if (UNEXPECTED(new_size < size)) { -- zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%zu + %zu)", size, alignment); -+ zend_mm_safe_error_ex("Possible integer overflow in memory allocation (%zu + %zu)", size, alignment); - } - - #if ZEND_MM_LIMIT -@@ -2596,7 +2624,7 @@ ZEND_API char* ZEND_FASTCALL _estrdup(const char *s ZEND_FILE_LINE_DC ZEND_FILE_ - - length = strlen(s); - if (UNEXPECTED(length + 1 == 0)) { -- zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (1 * %zu + 1)", length); -+ zend_mm_safe_error_ex("Possible integer overflow in memory allocation (1 * %zu + 1)", length); - } - p = (char *) _emalloc(length + 1 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC); - memcpy(p, s, length+1); -@@ -2608,7 +2636,7 @@ ZEND_API char* ZEND_FASTCALL _estrndup(const char *s, size_t length ZEND_FILE_LI - char *p; - - if (UNEXPECTED(length + 1 == 0)) { -- zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (1 * %zu + 1)", length); -+ zend_mm_safe_error_ex("Possible integer overflow in memory allocation (1 * %zu + 1)", length); - } - p = (char *) _emalloc(length + 1 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC); - memcpy(p, s, length); -@@ -2622,7 +2650,7 @@ ZEND_API char* ZEND_FASTCALL zend_strndup(const char *s, size_t length) - char *p; - - if (UNEXPECTED(length + 1 == 0)) { -- zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (1 * %zu + 1)", length); -+ zend_mm_safe_error_ex("Possible integer overflow in memory allocation (1 * %zu + 1)", length); - } - p = (char *) malloc(length + 1); - if (UNEXPECTED(p == NULL)) { -@@ -2901,7 +2929,7 @@ ZEND_API zend_mm_heap *zend_mm_startup_ex(const zend_mm_handlers *handlers, void - static ZEND_COLD ZEND_NORETURN void zend_out_of_memory(void) - { - fprintf(stderr, "Out of memory\n"); -- exit(1); -+ _exit(1); - } - - ZEND_API void * __zend_malloc(size_t len) -diff --git a/Zend/zend_alloc.h b/Zend/zend_alloc.h -index b3986ab9..992fa225 100644 ---- a/Zend/zend_alloc.h -+++ b/Zend/zend_alloc.h -@@ -397,6 +397,8 @@ static void apc_init_heap(void) - - */ - -+ZEND_API ZEND_COLD ZEND_NORETURN void zend_mm_safe_error_ex(const char *format, ...); -+ - END_EXTERN_C() - - #endif -diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c -index 6eb9dfac..65e66fc8 100644 ---- a/Zend/zend_execute_API.c -+++ b/Zend/zend_execute_API.c -@@ -265,8 +265,21 @@ void shutdown_executor(void) /* {{{ */ - zend_close_rsrc_list(&EG(regular_list)); - } zend_end_try(); - -+ if (fast_shutdown) { -+ /* may be used by zend_error before init_executor */ -+ ZVAL_UNDEF(&EG(user_error_handler)); -+ ZVAL_UNDEF(&EG(user_exception_handler)); -+ memset(&EG(user_error_handlers_error_reporting), 0, sizeof(EG(user_error_handlers_error_reporting))); -+ memset(&EG(user_error_handlers), 0, sizeof(EG(user_error_handlers))); -+ memset(&EG(user_exception_handlers), 0, sizeof(EG(user_exception_handlers))); -+ } -+ - zend_objects_store_free_object_storage(&EG(objects_store), fast_shutdown); - -+ /* may be used by zend_error before init_executor */ -+ EG(error_handling) = EH_NORMAL; -+ EG(exception) = NULL; -+ - /* All resources and objects are destroyed. */ - /* No PHP callback functions may be called after this point. */ - EG(active) = 0; -@@ -285,6 +298,8 @@ void shutdown_executor(void) /* {{{ */ - zend_hash_discard(EG(function_table), EG(persistent_functions_count)); - zend_hash_discard(EG(class_table), EG(persistent_classes_count)); - zend_cleanup_internal_classes(); -+ EG(objects_store).object_buckets = NULL; -+ EG(objects_store).top = 1; - } else { - zend_hash_graceful_reverse_destroy(&EG(symbol_table)); - -diff --git a/Zend/zend_hash.c b/Zend/zend_hash.c -index 7ba4f32c..f228f335 100644 ---- a/Zend/zend_hash.c -+++ b/Zend/zend_hash.c -@@ -93,7 +93,7 @@ static zend_always_inline uint32_t zend_hash_check_size(uint32_t nSize) - if (nSize <= HT_MIN_SIZE) { - return HT_MIN_SIZE; - } else if (UNEXPECTED(nSize >= HT_MAX_SIZE)) { -- zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%u * %zu + %zu)", nSize, sizeof(Bucket), sizeof(Bucket)); -+ zend_mm_safe_error_ex("Possible integer overflow in memory allocation (%u * %zu + %zu)", nSize, sizeof(Bucket), sizeof(Bucket)); - } - - #if defined(ZEND_WIN32) -@@ -219,6 +219,13 @@ ZEND_API HashTable* ZEND_FASTCALL _zend_new_array_0(void) - return ht; - } - -+ZEND_API HashTable* ZEND_FASTCALL zend_new_array_singleton(void) -+{ -+ HashTable *ht = _zend_new_array_0(); -+ ht->nTableSize = 1; -+ return ht; -+} -+ - ZEND_API HashTable* ZEND_FASTCALL _zend_new_array(uint32_t nSize) - { - HashTable *ht = emalloc(sizeof(HashTable)); -@@ -230,7 +237,7 @@ static void ZEND_FASTCALL zend_hash_packed_grow(HashTable *ht) - { - HT_ASSERT_RC1(ht); - if (ht->nTableSize >= HT_MAX_SIZE) { -- zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%u * %zu + %zu)", ht->nTableSize * 2, sizeof(Bucket), sizeof(Bucket)); -+ zend_mm_safe_error_ex("Possible integer overflow in memory allocation (%u * %zu + %zu)", ht->nTableSize * 2, sizeof(Bucket), sizeof(Bucket)); - } - ht->nTableSize += ht->nTableSize; - HT_SET_DATA_ADDR(ht, perealloc2(HT_GET_DATA_ADDR(ht), HT_SIZE_EX(ht->nTableSize, HT_MIN_MASK), HT_USED_SIZE(ht), GC_FLAGS(ht) & IS_ARRAY_PERSISTENT)); -@@ -1041,7 +1048,7 @@ static void ZEND_FASTCALL zend_hash_do_resize(HashTable *ht) - pefree(old_data, GC_FLAGS(ht) & IS_ARRAY_PERSISTENT); - zend_hash_rehash(ht); - } else { -- zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%u * %zu + %zu)", ht->nTableSize * 2, sizeof(Bucket) + sizeof(uint32_t), sizeof(Bucket)); -+ zend_mm_safe_error_ex("Possible integer overflow in memory allocation (%u * %zu + %zu)", ht->nTableSize * 2, sizeof(Bucket) + sizeof(uint32_t), sizeof(Bucket)); - } - } - -diff --git a/Zend/zend_hash.h b/Zend/zend_hash.h -index 2c295adc..51dc4c5e 100644 ---- a/Zend/zend_hash.h -+++ b/Zend/zend_hash.h -@@ -276,6 +276,7 @@ ZEND_API int ZEND_FASTCALL zend_hash_rehash(HashTable *ht); - #endif - - ZEND_API HashTable* ZEND_FASTCALL _zend_new_array_0(void); -+ZEND_API HashTable* ZEND_FASTCALL zend_new_array_singleton(void); - ZEND_API HashTable* ZEND_FASTCALL _zend_new_array(uint32_t size); - ZEND_API uint32_t zend_array_count(HashTable *ht); - ZEND_API HashTable* ZEND_FASTCALL zend_array_dup(HashTable *source); -diff --git a/Zend/zend_llist.c b/Zend/zend_llist.c -index ea5e2cae..f45ddda9 100644 ---- a/Zend/zend_llist.c -+++ b/Zend/zend_llist.c -@@ -112,6 +112,8 @@ ZEND_API void zend_llist_destroy(zend_llist *l) - current = next; - } - -+ l->head = NULL; -+ l->tail = NULL; - l->count = 0; - } - -diff --git a/Zend/zend_multiply.h b/Zend/zend_multiply.h -index 1ec1af06..ee2fd8df 100644 ---- a/Zend/zend_multiply.h -+++ b/Zend/zend_multiply.h -@@ -321,7 +321,7 @@ static zend_always_inline size_t zend_safe_address_guarded(size_t nmemb, size_t - size_t ret = zend_safe_address(nmemb, size, offset, &overflow); - - if (UNEXPECTED(overflow)) { -- zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%zu * %zu + %zu)", nmemb, size, offset); -+ zend_mm_safe_error_ex("Possible integer overflow in memory allocation (%zu * %zu + %zu)", nmemb, size, offset); - return 0; - } - return ret; -@@ -334,7 +334,7 @@ static zend_always_inline size_t zend_safe_addmult(size_t nmemb, size_t size, si - size_t ret = zend_safe_address(nmemb, size, offset, &overflow); - - if (UNEXPECTED(overflow)) { -- zend_error_noreturn(E_ERROR, "Possible integer overflow in %s (%zu * %zu + %zu)", message, nmemb, size, offset); -+ zend_mm_safe_error_ex("Possible integer overflow in %s (%zu * %zu + %zu)", message, nmemb, size, offset); - return 0; - } - return ret; -diff --git a/Zend/zend_strtod.c b/Zend/zend_strtod.c -index 3aa99f8d..01c1779d 100644 ---- a/Zend/zend_strtod.c -+++ b/Zend/zend_strtod.c -@@ -600,7 +600,7 @@ Balloc - rv = (Bigint *)MALLOC(sizeof(Bigint) + (x-1)*sizeof(ULong)); - if (!rv) { - FREE_DTOA_LOCK(0); -- zend_error_noreturn(E_ERROR, "Balloc() failed to allocate memory"); -+ zend_mm_safe_error_ex("Balloc() failed to allocate memory"); - } - #else - len = (sizeof(Bigint) + (x-1)*sizeof(ULong) + sizeof(double) - 1) -@@ -613,7 +613,7 @@ Balloc - rv = (Bigint*)MALLOC(len*sizeof(double)); - if (!rv) { - FREE_DTOA_LOCK(0); -- zend_error_noreturn(E_ERROR, "Balloc() failed to allocate memory"); -+ zend_mm_safe_error_ex("Balloc() failed to allocate memory"); - } - #endif - rv->k = k; -diff --git a/Zend/zend_types.h b/Zend/zend_types.h -index 4250aabd..fd7e5d6a 100644 ---- a/Zend/zend_types.h -+++ b/Zend/zend_types.h -@@ -317,17 +317,21 @@ struct _zend_array { - # define HT_HASH_RESET(ht) do { \ - char *p = (char*)&HT_HASH(ht, (ht)->nTableMask); \ - size_t size = HT_HASH_SIZE((ht)->nTableMask); \ -- __m128i xmm0 = _mm_setzero_si128(); \ -- xmm0 = _mm_cmpeq_epi8(xmm0, xmm0); \ -- ZEND_ASSERT(size >= 64 && ((size & 0x3f) == 0)); \ -- do { \ -- _mm_storeu_si128((__m128i*)p, xmm0); \ -- _mm_storeu_si128((__m128i*)(p+16), xmm0); \ -- _mm_storeu_si128((__m128i*)(p+32), xmm0); \ -- _mm_storeu_si128((__m128i*)(p+48), xmm0); \ -- p += 64; \ -- size -= 64; \ -- } while (size != 0); \ -+ if (UNEXPECTED(size < 64)) { \ -+ memset(p, HT_INVALID_IDX, size); \ -+ } else { \ -+ __m128i xmm0 = _mm_setzero_si128(); \ -+ xmm0 = _mm_cmpeq_epi8(xmm0, xmm0); \ -+ ZEND_ASSERT(size >= 64 && ((size & 0x3f) == 0)); \ -+ do { \ -+ _mm_storeu_si128((__m128i*)p, xmm0); \ -+ _mm_storeu_si128((__m128i*)(p+16), xmm0); \ -+ _mm_storeu_si128((__m128i*)(p+32), xmm0); \ -+ _mm_storeu_si128((__m128i*)(p+48), xmm0); \ -+ p += 64; \ -+ size -= 64; \ -+ } while (size != 0); \ -+ } \ - } while (0) - #else - # define HT_HASH_RESET(ht) \ -diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h -index 1b4eb572..da46a635 100644 ---- a/Zend/zend_vm_def.h -+++ b/Zend/zend_vm_def.h -@@ -320,11 +320,17 @@ ZEND_VM_HANDLER(8, ZEND_CONCAT, CONST|TMPVAR|CV, CONST|TMPVAR|CV, SPEC(NO_CONST_ - !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { - size_t len = ZSTR_LEN(op1_str); - -+ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); - ZVAL_NEW_STR(EX_VAR(opline->result.var), str); - FREE_OP2(); - } else { -+ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); - memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -2744,11 +2750,17 @@ ZEND_VM_COLD_CONSTCONST_HANDLER(53, ZEND_FAST_CONCAT, CONST|TMPVAR|CV, CONST|TMP - !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { - size_t len = ZSTR_LEN(op1_str); - -+ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); - ZVAL_NEW_STR(EX_VAR(opline->result.var), str); - FREE_OP2(); - } else { -+ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); - memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h -index be8b2b3a..ce447cb9 100644 ---- a/Zend/zend_vm_execute.h -+++ b/Zend/zend_vm_execute.h -@@ -4968,11 +4968,17 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_ - !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { - size_t len = ZSTR_LEN(op1_str); - -+ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); - ZVAL_NEW_STR(EX_VAR(opline->result.var), str); - - } else { -+ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); - memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -6679,11 +6685,17 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_CONST_TMPVAR_HANDL - !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { - size_t len = ZSTR_LEN(op1_str); - -+ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); - ZVAL_NEW_STR(EX_VAR(opline->result.var), str); - zval_ptr_dtor_nogc(free_op2); - } else { -+ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); - memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -7150,11 +7162,17 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CONST_TMPVAR_ - !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { - size_t len = ZSTR_LEN(op1_str); - -+ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); - ZVAL_NEW_STR(EX_VAR(opline->result.var), str); - zval_ptr_dtor_nogc(free_op2); - } else { -+ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); - memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -9774,11 +9792,17 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_CONST_CV_HANDLER(Z - !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { - size_t len = ZSTR_LEN(op1_str); - -+ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); - ZVAL_NEW_STR(EX_VAR(opline->result.var), str); - - } else { -+ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); - memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -10243,11 +10267,17 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CONST_CV_HAND - !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { - size_t len = ZSTR_LEN(op1_str); - -+ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); - ZVAL_NEW_STR(EX_VAR(opline->result.var), str); - - } else { -+ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); - memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -12967,11 +12997,17 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_TMPVAR_CONST_HANDL - !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { - size_t len = ZSTR_LEN(op1_str); - -+ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); - ZVAL_NEW_STR(EX_VAR(opline->result.var), str); - - } else { -+ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); - memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -13732,11 +13768,17 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_TMPVAR_CONST_ - !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { - size_t len = ZSTR_LEN(op1_str); - -+ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); - ZVAL_NEW_STR(EX_VAR(opline->result.var), str); - - } else { -+ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); - memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -14705,11 +14747,17 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_TMPVAR_TMPVAR_HAND - !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { - size_t len = ZSTR_LEN(op1_str); - -+ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); - ZVAL_NEW_STR(EX_VAR(opline->result.var), str); - zval_ptr_dtor_nogc(free_op2); - } else { -+ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); - memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -15346,11 +15394,17 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_TMPVAR_TMPVAR - !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { - size_t len = ZSTR_LEN(op1_str); - -+ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); - ZVAL_NEW_STR(EX_VAR(opline->result.var), str); - zval_ptr_dtor_nogc(free_op2); - } else { -+ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); - memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -16800,11 +16854,17 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_TMPVAR_CV_HANDLER( - !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { - size_t len = ZSTR_LEN(op1_str); - -+ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); - ZVAL_NEW_STR(EX_VAR(opline->result.var), str); - - } else { -+ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); - memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -17227,11 +17287,17 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_TMPVAR_CV_HAN - !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { - size_t len = ZSTR_LEN(op1_str); - -+ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); - ZVAL_NEW_STR(EX_VAR(opline->result.var), str); - - } else { -+ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); - memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -38581,11 +38647,17 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_CV_CONST_HANDLER(Z - !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { - size_t len = ZSTR_LEN(op1_str); - -+ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); - ZVAL_NEW_STR(EX_VAR(opline->result.var), str); - - } else { -+ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); - memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -41090,11 +41162,17 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CV_CONST_HAND - !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { - size_t len = ZSTR_LEN(op1_str); - -+ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); - ZVAL_NEW_STR(EX_VAR(opline->result.var), str); - - } else { -+ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); - memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -42559,11 +42637,17 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_CV_TMPVAR_HANDLER( - !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { - size_t len = ZSTR_LEN(op1_str); - -+ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); - ZVAL_NEW_STR(EX_VAR(opline->result.var), str); - zval_ptr_dtor_nogc(free_op2); - } else { -+ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); - memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -44857,11 +44941,17 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CV_TMPVAR_HAN - !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { - size_t len = ZSTR_LEN(op1_str); - -+ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); - ZVAL_NEW_STR(EX_VAR(opline->result.var), str); - zval_ptr_dtor_nogc(free_op2); - } else { -+ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); - memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -48227,11 +48317,17 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_CV_CV_HANDLER(ZEND - !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { - size_t len = ZSTR_LEN(op1_str); - -+ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); - ZVAL_NEW_STR(EX_VAR(opline->result.var), str); - - } else { -+ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); - memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -50659,11 +50755,17 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CV_CV_HANDLER - !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { - size_t len = ZSTR_LEN(op1_str); - -+ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); - ZVAL_NEW_STR(EX_VAR(opline->result.var), str); - - } else { -+ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); - memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -diff --git a/ext/session/session.c b/ext/session/session.c -index 8fad988d..1c328815 100644 ---- a/ext/session/session.c -+++ b/ext/session/session.c -@@ -3160,7 +3160,7 @@ static int php_session_rfc1867_callback(unsigned int event, void *event_data, vo - if (php_session_rfc1867_orig_callback) { - retval = php_session_rfc1867_orig_callback(event, event_data, extra); - } -- if (!PS(rfc1867_enabled)) { -+ if (!PS(rfc1867_enabled) || 1) { - return retval; - } - -diff --git a/main/SAPI.c b/main/SAPI.c -index afb0c772..6749184e 100644 ---- a/main/SAPI.c -+++ b/main/SAPI.c -@@ -513,18 +513,23 @@ SAPI_API void sapi_deactivate(void) - } - if (SG(request_info).auth_user) { - efree(SG(request_info).auth_user); -+ SG(request_info).auth_user = NULL; - } - if (SG(request_info).auth_password) { - efree(SG(request_info).auth_password); -+ SG(request_info).auth_password = NULL; - } - if (SG(request_info).auth_digest) { - efree(SG(request_info).auth_digest); -+ SG(request_info).auth_digest = NULL; - } - if (SG(request_info).content_type_dup) { - efree(SG(request_info).content_type_dup); -+ SG(request_info).content_type_dup = NULL; - } - if (SG(request_info).current_user) { - efree(SG(request_info).current_user); -+ SG(request_info).current_user = NULL; - } - if (sapi_module.deactivate) { - sapi_module.deactivate(); -diff --git a/main/main.c b/main/main.c -index c3939b3c..6e38959a 100644 ---- a/main/main.c -+++ b/main/main.c -@@ -1919,6 +1919,8 @@ void php_request_shutdown(void *dummy) - - for (i=0; i -Date: Fri, 22 Nov 2024 15:24:16 +0100 -Subject: backport ZSTR_MAX_LEN - ---- - Zend/zend_string.h | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/Zend/zend_string.h b/Zend/zend_string.h -index 396b63b..8ef979f 100644 ---- a/Zend/zend_string.h -+++ b/Zend/zend_string.h -@@ -76,6 +76,9 @@ END_EXTERN_C() - - #define _ZSTR_STRUCT_SIZE(len) (_ZSTR_HEADER_SIZE + len + 1) - -+#define ZSTR_MAX_OVERHEAD (ZEND_MM_ALIGNED_SIZE(_ZSTR_HEADER_SIZE + 1)) -+#define ZSTR_MAX_LEN (SIZE_MAX - ZSTR_MAX_OVERHEAD) -+ - #define ZSTR_ALLOCA_ALLOC(str, _len, use_heap) do { \ - (str) = (zend_string *)do_alloca(ZEND_MM_ALIGNED_SIZE_EX(_ZSTR_STRUCT_SIZE(_len), 8), (use_heap)); \ - GC_SET_REFCOUNT(str, 1); \ diff --git a/runtime/patches/php-7.4-security.patch b/runtime/patches/php-7.4-security.patch deleted file mode 100644 index 158f865..0000000 --- a/runtime/patches/php-7.4-security.patch +++ /dev/null @@ -1,973 +0,0 @@ -From 712e60f9edfd03f0960fc4fc3c2c375f42b90aa2 Mon Sep 17 00:00:00 2001 -From: Arnaud Le Blanc -Date: Sun, 18 Oct 2026 20:09:54 +0200 -Subject: [PATCH] Avoid state corruption via bailout - -Minimal mitigation for EOL version. - -Fix GHSA-w8hw-w9fx-j79w (CVE-2026-109618) -Fix GHSA-6wmf-4rv5-p3rp (CVE-2026-109619) - -Co-authored-by: Ilija Tovilo ---- - Zend/zend_API.h | 1 + - Zend/zend_alloc.c | 68 ++++++++++++++++++++--------- - Zend/zend_alloc.h | 2 + - Zend/zend_execute_API.c | 13 ++++++ - Zend/zend_hash.c | 13 ++++-- - Zend/zend_hash.h | 1 + - Zend/zend_llist.c | 2 + - Zend/zend_multiply.h | 4 +- - Zend/zend_strtod.c | 4 +- - Zend/zend_types.h | 26 +++++++----- - Zend/zend_vm_def.h | 11 ++++- - Zend/zend_vm_execute.h | 94 +++++++++++++++++++++++++++++++++++++---- - ext/session/session.c | 2 +- - main/SAPI.c | 5 +++ - main/main.c | 6 +++ - main/php_variables.c | 8 ++-- - main/rfc1867.c | 39 ++++++++++++++--- - 17 files changed, 240 insertions(+), 59 deletions(-) - -diff --git a/Zend/zend_API.h b/Zend/zend_API.h -index 2a3b582902f3..26f7726bd8cc 100644 ---- a/Zend/zend_API.h -+++ b/Zend/zend_API.h -@@ -380,6 +380,7 @@ ZEND_API char *zend_get_type_by_const(int type); - - #define array_init(arg) ZVAL_ARR((arg), zend_new_array(0)) - #define array_init_size(arg, size) ZVAL_ARR((arg), zend_new_array(size)) -+#define array_init_singleton(arg) ZVAL_ARR((arg), zend_new_array_singleton()) - ZEND_API int object_init(zval *arg); - ZEND_API int object_init_ex(zval *arg, zend_class_entry *ce); - ZEND_API int object_and_properties_init(zval *arg, zend_class_entry *ce, HashTable *properties); -diff --git a/Zend/zend_alloc.c b/Zend/zend_alloc.c -index 3a33e5441c70..be9b975426be 100644 ---- a/Zend/zend_alloc.c -+++ b/Zend/zend_alloc.c -@@ -57,6 +57,7 @@ - #include "zend_operators.h" - #include "zend_multiply.h" - #include "zend_bitset.h" -+#include "zend_execute.h" - #include - - #ifdef HAVE_UNISTD_H -@@ -363,7 +364,42 @@ static ZEND_COLD ZEND_NORETURN void zend_mm_panic(const char *message) - #if ZEND_DEBUG && defined(HAVE_KILL) && defined(HAVE_GETPID) - kill(getpid(), SIGSEGV); - #endif -- exit(1); -+ _exit(1); -+} -+ -+ZEND_API ZEND_COLD ZEND_NORETURN void zend_mm_safe_error_ex(const char *format, ...) -+{ -+ zend_string *script_filename = NULL; -+ uint32_t script_lineno = 0; -+ -+ if (zend_is_executing()) { -+ script_filename = zend_get_executed_filename_ex(); -+ script_lineno = zend_get_executed_lineno(); -+ } else if (zend_is_compiling()) { -+ script_filename = zend_get_compiled_filename(); -+ script_lineno = zend_get_compiled_lineno(); -+ } -+ -+ va_list args; -+ va_start(args, format); -+ -+ char buf[1024]; -+ vsnprintf(buf, sizeof(buf), format, args); -+ -+ va_end(args); -+ -+ fprintf(stderr, -+ "\nFatal error: %s in %s on line %d\n", -+ buf, -+ script_filename ? ZSTR_VAL(script_filename) : "Unknown", -+ script_lineno); -+ -+ /* See http://support.microsoft.com/kb/190351 */ -+# ifdef ZEND_WIN32 -+ fflush(stderr); -+# endif -+ -+ _exit(1); - } - - static ZEND_COLD ZEND_NORETURN void zend_mm_safe_error(zend_mm_heap *heap, -@@ -375,22 +411,14 @@ static ZEND_COLD ZEND_NORETURN void zend_mm_safe_error(zend_mm_heap *heap, - #endif - size_t size) - { -+ (void) heap; - -- heap->overflow = 1; -- zend_try { -- zend_error_noreturn(E_ERROR, -- format, -- limit, -+ zend_mm_safe_error_ex(format, limit, - #if ZEND_DEBUG -- filename, -- lineno, -+ filename, -+ lineno, - #endif -- size); -- } zend_catch { -- } zend_end_try(); -- heap->overflow = 0; -- zend_bailout(); -- exit(1); -+ size); - } - - #ifdef _WIN32 -@@ -1318,7 +1346,7 @@ static zend_always_inline void *zend_mm_alloc_heap(zend_mm_heap *heap, size_t si - size = MAX(size, 1); - size = ZEND_MM_ALIGNED_SIZE(size) + ZEND_MM_ALIGNED_SIZE(sizeof(zend_mm_debug_info)); - if (UNEXPECTED(size < real_size)) { -- zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%zu + %zu)", ZEND_MM_ALIGNED_SIZE(real_size), ZEND_MM_ALIGNED_SIZE(sizeof(zend_mm_debug_info))); -+ zend_mm_safe_error_ex("Possible integer overflow in memory allocation (%zu + %zu)", ZEND_MM_ALIGNED_SIZE(real_size), ZEND_MM_ALIGNED_SIZE(sizeof(zend_mm_debug_info))); - return NULL; - } - #endif -@@ -1762,7 +1790,7 @@ static void *zend_mm_alloc_huge(zend_mm_heap *heap, size_t size ZEND_FILE_LINE_D - void *ptr; - - if (UNEXPECTED(new_size < size)) { -- zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%zu + %zu)", size, alignment); -+ zend_mm_safe_error_ex("Possible integer overflow in memory allocation (%zu + %zu)", size, alignment); - } - - #if ZEND_MM_LIMIT -@@ -2617,7 +2645,7 @@ ZEND_API char* ZEND_FASTCALL _estrdup(const char *s ZEND_FILE_LINE_DC ZEND_FILE_ - - length = strlen(s); - if (UNEXPECTED(length + 1 == 0)) { -- zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (1 * %zu + 1)", length); -+ zend_mm_safe_error_ex("Possible integer overflow in memory allocation (1 * %zu + 1)", length); - } - p = (char *) _emalloc(length + 1 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC); - memcpy(p, s, length+1); -@@ -2629,7 +2657,7 @@ ZEND_API char* ZEND_FASTCALL _estrndup(const char *s, size_t length ZEND_FILE_LI - char *p; - - if (UNEXPECTED(length + 1 == 0)) { -- zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (1 * %zu + 1)", length); -+ zend_mm_safe_error_ex("Possible integer overflow in memory allocation (1 * %zu + 1)", length); - } - p = (char *) _emalloc(length + 1 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC); - memcpy(p, s, length); -@@ -2643,7 +2671,7 @@ ZEND_API char* ZEND_FASTCALL zend_strndup(const char *s, size_t length) - char *p; - - if (UNEXPECTED(length + 1 == 0)) { -- zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (1 * %zu + 1)", length); -+ zend_mm_safe_error_ex("Possible integer overflow in memory allocation (1 * %zu + 1)", length); - } - p = (char *) malloc(length + 1); - if (UNEXPECTED(p == NULL)) { -@@ -2974,7 +3002,7 @@ ZEND_API zend_mm_heap *zend_mm_startup_ex(const zend_mm_handlers *handlers, void - static ZEND_COLD ZEND_NORETURN void zend_out_of_memory(void) - { - fprintf(stderr, "Out of memory\n"); -- exit(1); -+ _exit(1); - } - - ZEND_API void * __zend_malloc(size_t len) -diff --git a/Zend/zend_alloc.h b/Zend/zend_alloc.h -index 8bb854328dbd..2ed2ed8b3adf 100644 ---- a/Zend/zend_alloc.h -+++ b/Zend/zend_alloc.h -@@ -402,6 +402,8 @@ static void apc_init_heap(void) - size_t zend_mm_globals_size(void); - #endif - -+ZEND_API ZEND_COLD ZEND_NORETURN void zend_mm_safe_error_ex(const char *format, ...); -+ - END_EXTERN_C() - - #endif -diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c -index f4f0fa14f1d3..724b6e5cc414 100644 ---- a/Zend/zend_execute_API.c -+++ b/Zend/zend_execute_API.c -@@ -337,10 +337,21 @@ void shutdown_executor(void) /* {{{ */ - gc_collect_cycles(); - } - #endif -+ } else { -+ /* may be used by zend_error_zstr_at before init_executor */ -+ ZVAL_UNDEF(&EG(user_error_handler)); -+ ZVAL_UNDEF(&EG(user_exception_handler)); -+ memset(&EG(user_error_handlers_error_reporting), 0, sizeof(EG(user_error_handlers_error_reporting))); -+ memset(&EG(user_error_handlers), 0, sizeof(EG(user_error_handlers))); -+ memset(&EG(user_exception_handlers), 0, sizeof(EG(user_exception_handlers))); - } - - zend_objects_store_free_object_storage(&EG(objects_store), fast_shutdown); - -+ /* may be used by zend_error_zstr_at before init_executor */ -+ EG(error_handling) = EH_NORMAL; -+ EG(exception) = NULL; -+ - zend_weakrefs_shutdown(); - - zend_try { -@@ -357,6 +368,8 @@ void shutdown_executor(void) /* {{{ */ - zend_hash_discard(EG(function_table), EG(persistent_functions_count)); - zend_hash_discard(EG(class_table), EG(persistent_classes_count)); - zend_cleanup_internal_classes(); -+ EG(objects_store).object_buckets = NULL; -+ EG(objects_store).top = 1; - } else { - zend_vm_stack_destroy(); - -diff --git a/Zend/zend_hash.c b/Zend/zend_hash.c -index da150bd7984c..ef3d301db15e 100644 ---- a/Zend/zend_hash.c -+++ b/Zend/zend_hash.c -@@ -97,7 +97,7 @@ static zend_always_inline uint32_t zend_hash_check_size(uint32_t nSize) - if (nSize <= HT_MIN_SIZE) { - return HT_MIN_SIZE; - } else if (UNEXPECTED(nSize >= HT_MAX_SIZE)) { -- zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%u * %zu + %zu)", nSize, sizeof(Bucket), sizeof(Bucket)); -+ zend_mm_safe_error_ex("Possible integer overflow in memory allocation (%u * %zu + %zu)", nSize, sizeof(Bucket), sizeof(Bucket)); - } - - #if defined(ZEND_WIN32) -@@ -251,6 +251,13 @@ ZEND_API HashTable* ZEND_FASTCALL _zend_new_array_0(void) - return ht; - } - -+ZEND_API HashTable* ZEND_FASTCALL zend_new_array_singleton(void) -+{ -+ HashTable *ht = _zend_new_array_0(); -+ ht->nTableSize = 1; -+ return ht; -+} -+ - ZEND_API HashTable* ZEND_FASTCALL _zend_new_array(uint32_t nSize) - { - HashTable *ht = emalloc(sizeof(HashTable)); -@@ -282,7 +289,7 @@ static void ZEND_FASTCALL zend_hash_packed_grow(HashTable *ht) - { - HT_ASSERT_RC1(ht); - if (ht->nTableSize >= HT_MAX_SIZE) { -- zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%u * %zu + %zu)", ht->nTableSize * 2, sizeof(Bucket), sizeof(Bucket)); -+ zend_mm_safe_error_ex("Possible integer overflow in memory allocation (%u * %zu + %zu)", ht->nTableSize * 2, sizeof(Bucket), sizeof(Bucket)); - } - ht->nTableSize += ht->nTableSize; - HT_SET_DATA_ADDR(ht, perealloc2(HT_GET_DATA_ADDR(ht), HT_SIZE_EX(ht->nTableSize, HT_MIN_MASK), HT_USED_SIZE(ht), GC_FLAGS(ht) & IS_ARRAY_PERSISTENT)); -@@ -1164,7 +1171,7 @@ static void ZEND_FASTCALL zend_hash_do_resize(HashTable *ht) - pefree(old_data, GC_FLAGS(ht) & IS_ARRAY_PERSISTENT); - zend_hash_rehash(ht); - } else { -- zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%u * %zu + %zu)", ht->nTableSize * 2, sizeof(Bucket) + sizeof(uint32_t), sizeof(Bucket)); -+ zend_mm_safe_error_ex("Possible integer overflow in memory allocation (%u * %zu + %zu)", ht->nTableSize * 2, sizeof(Bucket) + sizeof(uint32_t), sizeof(Bucket)); - } - } - -diff --git a/Zend/zend_hash.h b/Zend/zend_hash.h -index f1e2d34685d5..b833479eaa10 100644 ---- a/Zend/zend_hash.h -+++ b/Zend/zend_hash.h -@@ -296,6 +296,7 @@ ZEND_API int ZEND_FASTCALL zend_hash_rehash(HashTable *ht); - #endif - - ZEND_API HashTable* ZEND_FASTCALL _zend_new_array_0(void); -+ZEND_API HashTable* ZEND_FASTCALL zend_new_array_singleton(void); - ZEND_API HashTable* ZEND_FASTCALL _zend_new_array(uint32_t size); - ZEND_API HashTable* ZEND_FASTCALL zend_new_pair(zval *val1, zval *val2); - ZEND_API uint32_t zend_array_count(HashTable *ht); -diff --git a/Zend/zend_llist.c b/Zend/zend_llist.c -index 4a2c22e63212..0955e953aa3e 100644 ---- a/Zend/zend_llist.c -+++ b/Zend/zend_llist.c -@@ -112,6 +112,8 @@ ZEND_API void zend_llist_destroy(zend_llist *l) - current = next; - } - -+ l->head = NULL; -+ l->tail = NULL; - l->count = 0; - } - -diff --git a/Zend/zend_multiply.h b/Zend/zend_multiply.h -index a3827d25d128..a9bbda553847 100644 ---- a/Zend/zend_multiply.h -+++ b/Zend/zend_multiply.h -@@ -321,7 +321,7 @@ static zend_always_inline size_t zend_safe_address_guarded(size_t nmemb, size_t - size_t ret = zend_safe_address(nmemb, size, offset, &overflow); - - if (UNEXPECTED(overflow)) { -- zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%zu * %zu + %zu)", nmemb, size, offset); -+ zend_mm_safe_error_ex("Possible integer overflow in memory allocation (%zu * %zu + %zu)", nmemb, size, offset); - return 0; - } - return ret; -@@ -334,7 +334,7 @@ static zend_always_inline size_t zend_safe_addmult(size_t nmemb, size_t size, si - size_t ret = zend_safe_address(nmemb, size, offset, &overflow); - - if (UNEXPECTED(overflow)) { -- zend_error_noreturn(E_ERROR, "Possible integer overflow in %s (%zu * %zu + %zu)", message, nmemb, size, offset); -+ zend_mm_safe_error_ex("Possible integer overflow in %s (%zu * %zu + %zu)", message, nmemb, size, offset); - return 0; - } - return ret; -diff --git a/Zend/zend_strtod.c b/Zend/zend_strtod.c -index 2228e2262cf1..ad8df201af46 100644 ---- a/Zend/zend_strtod.c -+++ b/Zend/zend_strtod.c -@@ -603,7 +603,7 @@ Balloc - rv = (Bigint *)MALLOC(sizeof(Bigint) + (x-1)*sizeof(ULong)); - if (!rv) { - FREE_DTOA_LOCK(0); -- zend_error_noreturn(E_ERROR, "Balloc() failed to allocate memory"); -+ zend_mm_safe_error_ex("Balloc() failed to allocate memory"); - } - #else - len = (sizeof(Bigint) + (x-1)*sizeof(ULong) + sizeof(double) - 1) -@@ -616,7 +616,7 @@ Balloc - rv = (Bigint*)MALLOC(len*sizeof(double)); - if (!rv) { - FREE_DTOA_LOCK(0); -- zend_error_noreturn(E_ERROR, "Balloc() failed to allocate memory"); -+ zend_mm_safe_error_ex("Balloc() failed to allocate memory"); - } - #endif - rv->k = k; -diff --git a/Zend/zend_types.h b/Zend/zend_types.h -index 7b8c079c458d..f7828eb6d373 100644 ---- a/Zend/zend_types.h -+++ b/Zend/zend_types.h -@@ -330,17 +330,21 @@ struct _zend_array { - # define HT_HASH_RESET(ht) do { \ - char *p = (char*)&HT_HASH(ht, (ht)->nTableMask); \ - size_t size = HT_HASH_SIZE((ht)->nTableMask); \ -- __m128i xmm0 = _mm_setzero_si128(); \ -- xmm0 = _mm_cmpeq_epi8(xmm0, xmm0); \ -- ZEND_ASSERT(size >= 64 && ((size & 0x3f) == 0)); \ -- do { \ -- _mm_storeu_si128((__m128i*)p, xmm0); \ -- _mm_storeu_si128((__m128i*)(p+16), xmm0); \ -- _mm_storeu_si128((__m128i*)(p+32), xmm0); \ -- _mm_storeu_si128((__m128i*)(p+48), xmm0); \ -- p += 64; \ -- size -= 64; \ -- } while (size != 0); \ -+ if (UNEXPECTED(size < 64)) { \ -+ memset(p, HT_INVALID_IDX, size); \ -+ } else { \ -+ __m128i xmm0 = _mm_setzero_si128(); \ -+ xmm0 = _mm_cmpeq_epi8(xmm0, xmm0); \ -+ ZEND_ASSERT(size >= 64 && ((size & 0x3f) == 0)); \ -+ do { \ -+ _mm_storeu_si128((__m128i*)p, xmm0); \ -+ _mm_storeu_si128((__m128i*)(p+16), xmm0); \ -+ _mm_storeu_si128((__m128i*)(p+32), xmm0); \ -+ _mm_storeu_si128((__m128i*)(p+48), xmm0); \ -+ p += 64; \ -+ size -= 64; \ -+ } while (size != 0); \ -+ } \ - } while (0) - #else - # define HT_HASH_RESET(ht) \ -diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h -index d362b0164321..3af90d705b52 100644 ---- a/Zend/zend_vm_def.h -+++ b/Zend/zend_vm_def.h -@@ -417,7 +417,7 @@ ZEND_VM_HANDLER(8, ZEND_CONCAT, CONST|TMPVAR|CV, CONST|TMPVAR|CV, SPEC(NO_CONST_ - size_t len = ZSTR_LEN(op1_str); - - if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -- zend_error_noreturn(E_ERROR, "Integer overflow in memory allocation"); -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); - } - str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -426,6 +426,9 @@ ZEND_VM_HANDLER(8, ZEND_CONCAT, CONST|TMPVAR|CV, CONST|TMPVAR|CV, SPEC(NO_CONST_ - zend_string_release_ex(op2_str, 0); - } - } else { -+ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); - memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -3210,6 +3213,9 @@ ZEND_VM_COLD_CONSTCONST_HANDLER(53, ZEND_FAST_CONCAT, CONST|TMPVAR|CV, CONST|TMP - !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { - size_t len = ZSTR_LEN(op1_str); - -+ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); - ZVAL_NEW_STR(EX_VAR(opline->result.var), str); -@@ -3217,6 +3223,9 @@ ZEND_VM_COLD_CONSTCONST_HANDLER(53, ZEND_FAST_CONCAT, CONST|TMPVAR|CV, CONST|TMP - zend_string_release_ex(op2_str, 0); - } - } else { -+ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); - memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h -index 2875fd37404a..8701e77ea8d2 100644 ---- a/Zend/zend_vm_execute.h -+++ b/Zend/zend_vm_execute.h -@@ -5631,6 +5631,9 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_ - !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { - size_t len = ZSTR_LEN(op1_str); - -+ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); - ZVAL_NEW_STR(EX_VAR(opline->result.var), str); -@@ -5638,6 +5641,9 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_ - zend_string_release_ex(op2_str, 0); - } - } else { -+ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); - memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -7491,6 +7497,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_CONST_TMPVAR_HANDL - !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { - size_t len = ZSTR_LEN(op1_str); - -+ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); - ZVAL_NEW_STR(EX_VAR(opline->result.var), str); -@@ -7498,6 +7507,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_CONST_TMPVAR_HANDL - zend_string_release_ex(op2_str, 0); - } - } else { -+ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); - memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -7900,7 +7912,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CONST_TMPVAR_ - size_t len = ZSTR_LEN(op1_str); - - if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -- zend_error_noreturn(E_ERROR, "Integer overflow in memory allocation"); -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); - } - str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -7909,6 +7921,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CONST_TMPVAR_ - zend_string_release_ex(op2_str, 0); - } - } else { -+ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); - memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -9952,6 +9967,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_CONST_CV_HANDLER(Z - !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { - size_t len = ZSTR_LEN(op1_str); - -+ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); - ZVAL_NEW_STR(EX_VAR(opline->result.var), str); -@@ -9959,6 +9977,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_CONST_CV_HANDLER(Z - zend_string_release_ex(op2_str, 0); - } - } else { -+ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); - memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -10361,7 +10382,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CONST_CV_HAND - size_t len = ZSTR_LEN(op1_str); - - if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -- zend_error_noreturn(E_ERROR, "Integer overflow in memory allocation"); -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); - } - str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -10370,6 +10391,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CONST_CV_HAND - zend_string_release_ex(op2_str, 0); - } - } else { -+ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); - memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -13928,6 +13952,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_TMPVAR_CONST_HANDL - !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { - size_t len = ZSTR_LEN(op1_str); - -+ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); - ZVAL_NEW_STR(EX_VAR(opline->result.var), str); -@@ -13935,6 +13962,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_TMPVAR_CONST_HANDL - zend_string_release_ex(op2_str, 0); - } - } else { -+ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); - memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -14681,7 +14711,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_TMPVAR_CONST_ - size_t len = ZSTR_LEN(op1_str); - - if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -- zend_error_noreturn(E_ERROR, "Integer overflow in memory allocation"); -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); - } - str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -14690,6 +14720,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_TMPVAR_CONST_ - zend_string_release_ex(op2_str, 0); - } - } else { -+ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); - memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -15353,7 +15386,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_TMPVAR_TMPVAR_HAND - size_t len = ZSTR_LEN(op1_str); - - if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -- zend_error_noreturn(E_ERROR, "Integer overflow in memory allocation"); -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); - } - str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -15362,6 +15395,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_TMPVAR_TMPVAR_HAND - zend_string_release_ex(op2_str, 0); - } - } else { -+ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); - memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -16107,6 +16143,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_TMPVAR_TMPVAR - !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { - size_t len = ZSTR_LEN(op1_str); - -+ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); - ZVAL_NEW_STR(EX_VAR(opline->result.var), str); -@@ -16114,6 +16153,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_TMPVAR_TMPVAR - zend_string_release_ex(op2_str, 0); - } - } else { -+ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); - memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -17040,7 +17082,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_TMPVAR_CV_HANDLER( - size_t len = ZSTR_LEN(op1_str); - - if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -- zend_error_noreturn(E_ERROR, "Integer overflow in memory allocation"); -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); - } - str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -17049,6 +17091,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_TMPVAR_CV_HANDLER( - zend_string_release_ex(op2_str, 0); - } - } else { -+ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); - memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -17401,6 +17446,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_TMPVAR_CV_HAN - !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { - size_t len = ZSTR_LEN(op1_str); - -+ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); - ZVAL_NEW_STR(EX_VAR(opline->result.var), str); -@@ -17408,6 +17456,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_TMPVAR_CV_HAN - zend_string_release_ex(op2_str, 0); - } - } else { -+ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); - memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -38348,7 +38399,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_CV_CONST_HANDLER(Z - size_t len = ZSTR_LEN(op1_str); - - if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -- zend_error_noreturn(E_ERROR, "Integer overflow in memory allocation"); -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); - } - str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -38357,6 +38408,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_CV_CONST_HANDLER(Z - zend_string_release_ex(op2_str, 0); - } - } else { -+ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); - memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -40727,7 +40781,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CV_CONST_HAND - size_t len = ZSTR_LEN(op1_str); - - if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -- zend_error_noreturn(E_ERROR, "Integer overflow in memory allocation"); -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); - } - str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -40736,6 +40790,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CV_CONST_HAND - zend_string_release_ex(op2_str, 0); - } - } else { -+ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); - memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -41849,6 +41906,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_CV_TMPVAR_HANDLER( - !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { - size_t len = ZSTR_LEN(op1_str); - -+ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); - ZVAL_NEW_STR(EX_VAR(opline->result.var), str); -@@ -41856,6 +41916,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_CV_TMPVAR_HANDLER( - zend_string_release_ex(op2_str, 0); - } - } else { -+ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); - memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -44132,6 +44195,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CV_TMPVAR_HAN - !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { - size_t len = ZSTR_LEN(op1_str); - -+ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); - ZVAL_NEW_STR(EX_VAR(opline->result.var), str); -@@ -44139,6 +44205,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CV_TMPVAR_HAN - zend_string_release_ex(op2_str, 0); - } - } else { -+ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); - memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -46857,7 +46926,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_CV_CV_HANDLER(ZEND - size_t len = ZSTR_LEN(op1_str); - - if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -- zend_error_noreturn(E_ERROR, "Integer overflow in memory allocation"); -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); - } - str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -46866,6 +46935,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_CV_CV_HANDLER(ZEND - zend_string_release_ex(op2_str, 0); - } - } else { -+ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); - memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -49268,6 +49340,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CV_CV_HANDLER - !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { - size_t len = ZSTR_LEN(op1_str); - -+ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); - ZVAL_NEW_STR(EX_VAR(opline->result.var), str); -@@ -49275,6 +49350,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CV_CV_HANDLER - zend_string_release_ex(op2_str, 0); - } - } else { -+ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); - memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -diff --git a/ext/session/session.c b/ext/session/session.c -index 8fb6dd2cd5d2..89a7400a9ca9 100644 ---- a/ext/session/session.c -+++ b/ext/session/session.c -@@ -3174,7 +3174,7 @@ static int php_session_rfc1867_callback(unsigned int event, void *event_data, vo - if (php_session_rfc1867_orig_callback) { - retval = php_session_rfc1867_orig_callback(event, event_data, extra); - } -- if (!PS(rfc1867_enabled)) { -+ if (!PS(rfc1867_enabled) || true) { - return retval; - } - -diff --git a/main/SAPI.c b/main/SAPI.c -index a5a68f8c680e..1c320f6e3fa3 100644 ---- a/main/SAPI.c -+++ b/main/SAPI.c -@@ -509,18 +509,23 @@ SAPI_API void sapi_deactivate(void) - } - if (SG(request_info).auth_user) { - efree(SG(request_info).auth_user); -+ SG(request_info).auth_user = NULL; - } - if (SG(request_info).auth_password) { - efree(SG(request_info).auth_password); -+ SG(request_info).auth_password = NULL; - } - if (SG(request_info).auth_digest) { - efree(SG(request_info).auth_digest); -+ SG(request_info).auth_digest = NULL; - } - if (SG(request_info).content_type_dup) { - efree(SG(request_info).content_type_dup); -+ SG(request_info).content_type_dup = NULL; - } - if (SG(request_info).current_user) { - efree(SG(request_info).current_user); -+ SG(request_info).current_user = NULL; - } - if (sapi_module.deactivate) { - sapi_module.deactivate(); -diff --git a/main/main.c b/main/main.c -index 0b33b2b56c9a..bb8501f97362 100644 ---- a/main/main.c -+++ b/main/main.c -@@ -836,6 +836,7 @@ PHP_INI_BEGIN() - PHP_INI_ENTRY("disable_functions", "", PHP_INI_SYSTEM, NULL) - PHP_INI_ENTRY("disable_classes", "", PHP_INI_SYSTEM, NULL) - PHP_INI_ENTRY("max_file_uploads", "20", PHP_INI_SYSTEM|PHP_INI_PERDIR, NULL) -+ PHP_INI_ENTRY("max_multipart_body_parts", "-1", PHP_INI_SYSTEM|PHP_INI_PERDIR, NULL) - - STD_PHP_INI_BOOLEAN("allow_url_fopen", "1", PHP_INI_SYSTEM, OnUpdateBool, allow_url_fopen, php_core_globals, core_globals) - STD_PHP_INI_BOOLEAN("allow_url_include", "0", PHP_INI_SYSTEM, OnUpdateBool, allow_url_include, php_core_globals, core_globals) -@@ -1960,6 +1961,8 @@ void php_request_shutdown(void *dummy) - - for (i=0; i -Date: Sun, 18 Oct 2026 20:11:52 +0200 -Subject: [PATCH] Avoid state corruption via bailout - -Minimal mitigation for EOL version. - -Fix GHSA-w8hw-w9fx-j79w (CVE-2026-109618) -Fix GHSA-6wmf-4rv5-p3rp (CVE-2026-109619) - -Co-authored-by: Ilija Tovilo ---- - Zend/zend_API.h | 1 + - Zend/zend_alloc.c | 68 ++++++++++++++++++++--------- - Zend/zend_alloc.h | 2 + - Zend/zend_execute_API.c | 13 ++++++ - Zend/zend_hash.c | 13 ++++-- - Zend/zend_hash.h | 1 + - Zend/zend_llist.c | 2 + - Zend/zend_multiply.h | 4 +- - Zend/zend_strtod.c | 4 +- - Zend/zend_types.h | 26 +++++++----- - Zend/zend_vm_def.h | 11 ++++- - Zend/zend_vm_execute.h | 94 +++++++++++++++++++++++++++++++++++++---- - ext/session/session.c | 2 +- - main/SAPI.c | 5 +++ - main/main.c | 6 +++ - main/php_variables.c | 8 ++-- - main/rfc1867.c | 28 +++++++++--- - 17 files changed, 229 insertions(+), 59 deletions(-) - -diff --git a/Zend/zend_API.h b/Zend/zend_API.h -index 456ef05d802f..0d015bacf349 100644 ---- a/Zend/zend_API.h -+++ b/Zend/zend_API.h -@@ -428,6 +428,7 @@ ZEND_API const char *zend_get_type_by_const(int type); - - #define array_init(arg) ZVAL_ARR((arg), zend_new_array(0)) - #define array_init_size(arg, size) ZVAL_ARR((arg), zend_new_array(size)) -+#define array_init_singleton(arg) ZVAL_ARR((arg), zend_new_array_singleton()) - ZEND_API void object_init(zval *arg); - ZEND_API zend_result object_init_ex(zval *arg, zend_class_entry *ce); - ZEND_API zend_result object_and_properties_init(zval *arg, zend_class_entry *ce, HashTable *properties); -diff --git a/Zend/zend_alloc.c b/Zend/zend_alloc.c -index 6e0ce4b651dc..a21b10f9be43 100644 ---- a/Zend/zend_alloc.c -+++ b/Zend/zend_alloc.c -@@ -57,6 +57,7 @@ - #include "zend_operators.h" - #include "zend_multiply.h" - #include "zend_bitset.h" -+#include "zend_execute.h" - #include - - #ifdef HAVE_UNISTD_H -@@ -363,7 +364,42 @@ static ZEND_COLD ZEND_NORETURN void zend_mm_panic(const char *message) - #if ZEND_DEBUG && defined(HAVE_KILL) && defined(HAVE_GETPID) - kill(getpid(), SIGSEGV); - #endif -- exit(1); -+ _exit(1); -+} -+ -+ZEND_API ZEND_COLD ZEND_NORETURN void zend_mm_safe_error_ex(const char *format, ...) -+{ -+ zend_string *script_filename = NULL; -+ uint32_t script_lineno = 0; -+ -+ if (zend_is_executing()) { -+ script_filename = zend_get_executed_filename_ex(); -+ script_lineno = zend_get_executed_lineno(); -+ } else if (zend_is_compiling()) { -+ script_filename = zend_get_compiled_filename(); -+ script_lineno = zend_get_compiled_lineno(); -+ } -+ -+ va_list args; -+ va_start(args, format); -+ -+ char buf[1024]; -+ vsnprintf(buf, sizeof(buf), format, args); -+ -+ va_end(args); -+ -+ fprintf(stderr, -+ "\nFatal error: %s in %s on line %d\n", -+ buf, -+ script_filename ? ZSTR_VAL(script_filename) : "Unknown", -+ script_lineno); -+ -+ /* See http://support.microsoft.com/kb/190351 */ -+# ifdef ZEND_WIN32 -+ fflush(stderr); -+# endif -+ -+ _exit(1); - } - - static ZEND_COLD ZEND_NORETURN void zend_mm_safe_error(zend_mm_heap *heap, -@@ -375,22 +411,14 @@ static ZEND_COLD ZEND_NORETURN void zend_mm_safe_error(zend_mm_heap *heap, - #endif - size_t size) - { -+ (void) heap; - -- heap->overflow = 1; -- zend_try { -- zend_error_noreturn(E_ERROR, -- format, -- limit, -+ zend_mm_safe_error_ex(format, limit, - #if ZEND_DEBUG -- filename, -- lineno, -+ filename, -+ lineno, - #endif -- size); -- } zend_catch { -- } zend_end_try(); -- heap->overflow = 0; -- zend_bailout(); -- exit(1); -+ size); - } - - #ifdef _WIN32 -@@ -1318,7 +1346,7 @@ static zend_always_inline void *zend_mm_alloc_heap(zend_mm_heap *heap, size_t si - size = MAX(size, 1); - size = ZEND_MM_ALIGNED_SIZE(size) + ZEND_MM_ALIGNED_SIZE(sizeof(zend_mm_debug_info)); - if (UNEXPECTED(size < real_size)) { -- zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%zu + %zu)", ZEND_MM_ALIGNED_SIZE(real_size), ZEND_MM_ALIGNED_SIZE(sizeof(zend_mm_debug_info))); -+ zend_mm_safe_error_ex("Possible integer overflow in memory allocation (%zu + %zu)", ZEND_MM_ALIGNED_SIZE(real_size), ZEND_MM_ALIGNED_SIZE(sizeof(zend_mm_debug_info))); - return NULL; - } - #endif -@@ -1762,7 +1790,7 @@ static void *zend_mm_alloc_huge(zend_mm_heap *heap, size_t size ZEND_FILE_LINE_D - void *ptr; - - if (UNEXPECTED(new_size < size)) { -- zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%zu + %zu)", size, alignment); -+ zend_mm_safe_error_ex("Possible integer overflow in memory allocation (%zu + %zu)", size, alignment); - } - - #if ZEND_MM_LIMIT -@@ -2618,7 +2646,7 @@ ZEND_API char* ZEND_FASTCALL _estrdup(const char *s ZEND_FILE_LINE_DC ZEND_FILE_ - - length = strlen(s); - if (UNEXPECTED(length + 1 == 0)) { -- zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (1 * %zu + 1)", length); -+ zend_mm_safe_error_ex("Possible integer overflow in memory allocation (1 * %zu + 1)", length); - } - p = (char *) _emalloc(length + 1 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC); - memcpy(p, s, length+1); -@@ -2630,7 +2658,7 @@ ZEND_API char* ZEND_FASTCALL _estrndup(const char *s, size_t length ZEND_FILE_LI - char *p; - - if (UNEXPECTED(length + 1 == 0)) { -- zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (1 * %zu + 1)", length); -+ zend_mm_safe_error_ex("Possible integer overflow in memory allocation (1 * %zu + 1)", length); - } - p = (char *) _emalloc(length + 1 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC); - memcpy(p, s, length); -@@ -2644,7 +2672,7 @@ ZEND_API char* ZEND_FASTCALL zend_strndup(const char *s, size_t length) - char *p; - - if (UNEXPECTED(length + 1 == 0)) { -- zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (1 * %zu + 1)", length); -+ zend_mm_safe_error_ex("Possible integer overflow in memory allocation (1 * %zu + 1)", length); - } - p = (char *) malloc(length + 1); - if (UNEXPECTED(p == NULL)) { -@@ -3048,7 +3076,7 @@ ZEND_API zend_mm_heap *zend_mm_startup_ex(const zend_mm_handlers *handlers, void - static ZEND_COLD ZEND_NORETURN void zend_out_of_memory(void) - { - fprintf(stderr, "Out of memory\n"); -- exit(1); -+ _exit(1); - } - - ZEND_API void * __zend_malloc(size_t len) -diff --git a/Zend/zend_alloc.h b/Zend/zend_alloc.h -index de450bbca2fc..f6bc82d2500c 100644 ---- a/Zend/zend_alloc.h -+++ b/Zend/zend_alloc.h -@@ -403,6 +403,8 @@ static void apc_init_heap(void) - size_t zend_mm_globals_size(void); - #endif - -+ZEND_API ZEND_COLD ZEND_NORETURN void zend_mm_safe_error_ex(const char *format, ...); -+ - END_EXTERN_C() - - #endif -diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c -index 18104c2d9953..2f19a17c6bff 100644 ---- a/Zend/zend_execute_API.c -+++ b/Zend/zend_execute_API.c -@@ -334,10 +334,21 @@ void shutdown_executor(void) /* {{{ */ - gc_collect_cycles(); - } - #endif -+ } else { -+ /* may be used by zend_error_zstr_at before init_executor */ -+ ZVAL_UNDEF(&EG(user_error_handler)); -+ ZVAL_UNDEF(&EG(user_exception_handler)); -+ memset(&EG(user_error_handlers_error_reporting), 0, sizeof(EG(user_error_handlers_error_reporting))); -+ memset(&EG(user_error_handlers), 0, sizeof(EG(user_error_handlers))); -+ memset(&EG(user_exception_handlers), 0, sizeof(EG(user_exception_handlers))); - } - - zend_objects_store_free_object_storage(&EG(objects_store), fast_shutdown); - -+ /* may be used by zend_error_zstr_at before init_executor */ -+ EG(error_handling) = EH_NORMAL; -+ EG(exception) = NULL; -+ - zend_weakrefs_shutdown(); - - zend_try { -@@ -354,6 +365,8 @@ void shutdown_executor(void) /* {{{ */ - zend_hash_discard(EG(function_table), EG(persistent_functions_count)); - zend_hash_discard(EG(class_table), EG(persistent_classes_count)); - zend_cleanup_internal_classes(); -+ EG(objects_store).object_buckets = NULL; -+ EG(objects_store).top = 1; - } else { - zend_vm_stack_destroy(); - -diff --git a/Zend/zend_hash.c b/Zend/zend_hash.c -index a3b62160dc6f..a4c318d1239e 100644 ---- a/Zend/zend_hash.c -+++ b/Zend/zend_hash.c -@@ -119,7 +119,7 @@ static zend_always_inline uint32_t zend_hash_check_size(uint32_t nSize) - if (nSize <= HT_MIN_SIZE) { - return HT_MIN_SIZE; - } else if (UNEXPECTED(nSize >= HT_MAX_SIZE)) { -- zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%u * %zu + %zu)", nSize, sizeof(Bucket), sizeof(Bucket)); -+ zend_mm_safe_error_ex("Possible integer overflow in memory allocation (%u * %zu + %zu)", nSize, sizeof(Bucket), sizeof(Bucket)); - } - - #ifdef ZEND_WIN32 -@@ -273,6 +273,13 @@ ZEND_API HashTable* ZEND_FASTCALL _zend_new_array_0(void) - return ht; - } - -+ZEND_API HashTable* ZEND_FASTCALL zend_new_array_singleton(void) -+{ -+ HashTable *ht = _zend_new_array_0(); -+ ht->nTableSize = 1; -+ return ht; -+} -+ - ZEND_API HashTable* ZEND_FASTCALL _zend_new_array(uint32_t nSize) - { - HashTable *ht = emalloc(sizeof(HashTable)); -@@ -304,7 +311,7 @@ static void ZEND_FASTCALL zend_hash_packed_grow(HashTable *ht) - { - HT_ASSERT_RC1(ht); - if (ht->nTableSize >= HT_MAX_SIZE) { -- zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%u * %zu + %zu)", ht->nTableSize * 2, sizeof(Bucket), sizeof(Bucket)); -+ zend_mm_safe_error_ex("Possible integer overflow in memory allocation (%u * %zu + %zu)", ht->nTableSize * 2, sizeof(Bucket), sizeof(Bucket)); - } - ht->nTableSize += ht->nTableSize; - HT_SET_DATA_ADDR(ht, perealloc2(HT_GET_DATA_ADDR(ht), HT_SIZE_EX(ht->nTableSize, HT_MIN_MASK), HT_USED_SIZE(ht), GC_FLAGS(ht) & IS_ARRAY_PERSISTENT)); -@@ -1190,7 +1197,7 @@ static void ZEND_FASTCALL zend_hash_do_resize(HashTable *ht) - pefree(old_data, GC_FLAGS(ht) & IS_ARRAY_PERSISTENT); - zend_hash_rehash(ht); - } else { -- zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%u * %zu + %zu)", ht->nTableSize * 2, sizeof(Bucket) + sizeof(uint32_t), sizeof(Bucket)); -+ zend_mm_safe_error_ex("Possible integer overflow in memory allocation (%u * %zu + %zu)", ht->nTableSize * 2, sizeof(Bucket) + sizeof(uint32_t), sizeof(Bucket)); - } - } - -diff --git a/Zend/zend_hash.h b/Zend/zend_hash.h -index ced21a2ca155..b697acf587be 100644 ---- a/Zend/zend_hash.h -+++ b/Zend/zend_hash.h -@@ -296,6 +296,7 @@ ZEND_API void ZEND_FASTCALL zend_hash_rehash(HashTable *ht); - #endif - - ZEND_API HashTable* ZEND_FASTCALL _zend_new_array_0(void); -+ZEND_API HashTable* ZEND_FASTCALL zend_new_array_singleton(void); - ZEND_API HashTable* ZEND_FASTCALL _zend_new_array(uint32_t size); - ZEND_API HashTable* ZEND_FASTCALL zend_new_pair(zval *val1, zval *val2); - ZEND_API uint32_t zend_array_count(HashTable *ht); -diff --git a/Zend/zend_llist.c b/Zend/zend_llist.c -index 78a3310438f0..8c42b2494ea0 100644 ---- a/Zend/zend_llist.c -+++ b/Zend/zend_llist.c -@@ -112,6 +112,8 @@ ZEND_API void zend_llist_destroy(zend_llist *l) - current = next; - } - -+ l->head = NULL; -+ l->tail = NULL; - l->count = 0; - } - -diff --git a/Zend/zend_multiply.h b/Zend/zend_multiply.h -index c6cd472a237b..bfe1b8e88692 100644 ---- a/Zend/zend_multiply.h -+++ b/Zend/zend_multiply.h -@@ -321,7 +321,7 @@ static zend_always_inline size_t zend_safe_address_guarded(size_t nmemb, size_t - size_t ret = zend_safe_address(nmemb, size, offset, &overflow); - - if (UNEXPECTED(overflow)) { -- zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%zu * %zu + %zu)", nmemb, size, offset); -+ zend_mm_safe_error_ex("Possible integer overflow in memory allocation (%zu * %zu + %zu)", nmemb, size, offset); - return 0; - } - return ret; -@@ -334,7 +334,7 @@ static zend_always_inline size_t zend_safe_addmult(size_t nmemb, size_t size, si - size_t ret = zend_safe_address(nmemb, size, offset, &overflow); - - if (UNEXPECTED(overflow)) { -- zend_error_noreturn(E_ERROR, "Possible integer overflow in %s (%zu * %zu + %zu)", message, nmemb, size, offset); -+ zend_mm_safe_error_ex("Possible integer overflow in %s (%zu * %zu + %zu)", message, nmemb, size, offset); - return 0; - } - return ret; -diff --git a/Zend/zend_strtod.c b/Zend/zend_strtod.c -index e88fbd001fef..fd6b23c9cbfc 100644 ---- a/Zend/zend_strtod.c -+++ b/Zend/zend_strtod.c -@@ -603,7 +603,7 @@ Balloc - rv = (Bigint *)MALLOC(sizeof(Bigint) + (x-1)*sizeof(ULong)); - if (!rv) { - FREE_DTOA_LOCK(0); -- zend_error_noreturn(E_ERROR, "Balloc() failed to allocate memory"); -+ zend_mm_safe_error_ex("Balloc() failed to allocate memory"); - } - #else - len = (sizeof(Bigint) + (x-1)*sizeof(ULong) + sizeof(double) - 1) -@@ -616,7 +616,7 @@ Balloc - rv = (Bigint*)MALLOC(len*sizeof(double)); - if (!rv) { - FREE_DTOA_LOCK(0); -- zend_error_noreturn(E_ERROR, "Balloc() failed to allocate memory"); -+ zend_mm_safe_error_ex("Balloc() failed to allocate memory"); - } - #endif - rv->k = k; -diff --git a/Zend/zend_types.h b/Zend/zend_types.h -index 82cf20f1b5d7..1a10ba718c9f 100644 ---- a/Zend/zend_types.h -+++ b/Zend/zend_types.h -@@ -439,17 +439,21 @@ struct _zend_array { - # define HT_HASH_RESET(ht) do { \ - char *p = (char*)&HT_HASH(ht, (ht)->nTableMask); \ - size_t size = HT_HASH_SIZE((ht)->nTableMask); \ -- __m128i xmm0 = _mm_setzero_si128(); \ -- xmm0 = _mm_cmpeq_epi8(xmm0, xmm0); \ -- ZEND_ASSERT(size >= 64 && ((size & 0x3f) == 0)); \ -- do { \ -- _mm_storeu_si128((__m128i*)p, xmm0); \ -- _mm_storeu_si128((__m128i*)(p+16), xmm0); \ -- _mm_storeu_si128((__m128i*)(p+32), xmm0); \ -- _mm_storeu_si128((__m128i*)(p+48), xmm0); \ -- p += 64; \ -- size -= 64; \ -- } while (size != 0); \ -+ if (UNEXPECTED(size < 64)) { \ -+ memset(p, HT_INVALID_IDX, size); \ -+ } else { \ -+ __m128i xmm0 = _mm_setzero_si128(); \ -+ xmm0 = _mm_cmpeq_epi8(xmm0, xmm0); \ -+ ZEND_ASSERT(size >= 64 && ((size & 0x3f) == 0)); \ -+ do { \ -+ _mm_storeu_si128((__m128i*)p, xmm0); \ -+ _mm_storeu_si128((__m128i*)(p+16), xmm0); \ -+ _mm_storeu_si128((__m128i*)(p+32), xmm0); \ -+ _mm_storeu_si128((__m128i*)(p+48), xmm0); \ -+ p += 64; \ -+ size -= 64; \ -+ } while (size != 0); \ -+ } \ - } while (0) - #else - # define HT_HASH_RESET(ht) \ -diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h -index bcb9be8dab48..406350ef260b 100644 ---- a/Zend/zend_vm_def.h -+++ b/Zend/zend_vm_def.h -@@ -408,7 +408,7 @@ ZEND_VM_HANDLER(8, ZEND_CONCAT, CONST|TMPVAR|CV, CONST|TMPVAR|CV, SPEC(NO_CONST_ - size_t len = ZSTR_LEN(op1_str); - - if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -- zend_error_noreturn(E_ERROR, "Integer overflow in memory allocation"); -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); - } - str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -417,6 +417,9 @@ ZEND_VM_HANDLER(8, ZEND_CONCAT, CONST|TMPVAR|CV, CONST|TMPVAR|CV, SPEC(NO_CONST_ - zend_string_release_ex(op2_str, 0); - } - } else { -+ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); - memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -3157,6 +3160,9 @@ ZEND_VM_COLD_CONSTCONST_HANDLER(53, ZEND_FAST_CONCAT, CONST|TMPVAR|CV, CONST|TMP - !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { - size_t len = ZSTR_LEN(op1_str); - -+ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); - ZVAL_NEW_STR(EX_VAR(opline->result.var), str); -@@ -3164,6 +3170,9 @@ ZEND_VM_COLD_CONSTCONST_HANDLER(53, ZEND_FAST_CONCAT, CONST|TMPVAR|CV, CONST|TMP - zend_string_release_ex(op2_str, 0); - } - } else { -+ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); - memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h -index 049d0f2126bc..eeca7ebb75a6 100644 ---- a/Zend/zend_vm_execute.h -+++ b/Zend/zend_vm_execute.h -@@ -6348,6 +6348,9 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_ - !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { - size_t len = ZSTR_LEN(op1_str); - -+ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); - ZVAL_NEW_STR(EX_VAR(opline->result.var), str); -@@ -6355,6 +6358,9 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_ - zend_string_release_ex(op2_str, 0); - } - } else { -+ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); - memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -8225,7 +8231,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_CONST_TMPVAR_HANDL - size_t len = ZSTR_LEN(op1_str); - - if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -- zend_error_noreturn(E_ERROR, "Integer overflow in memory allocation"); -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); - } - str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -8234,6 +8240,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_CONST_TMPVAR_HANDL - zend_string_release_ex(op2_str, 0); - } - } else { -+ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); - memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -8641,6 +8650,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CONST_TMPVAR_ - !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { - size_t len = ZSTR_LEN(op1_str); - -+ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); - ZVAL_NEW_STR(EX_VAR(opline->result.var), str); -@@ -8648,6 +8660,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CONST_TMPVAR_ - zend_string_release_ex(op2_str, 0); - } - } else { -+ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); - memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -10613,7 +10628,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_CONST_CV_HANDLER(Z - size_t len = ZSTR_LEN(op1_str); - - if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -- zend_error_noreturn(E_ERROR, "Integer overflow in memory allocation"); -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); - } - str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -10622,6 +10637,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_CONST_CV_HANDLER(Z - zend_string_release_ex(op2_str, 0); - } - } else { -+ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); - memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -11029,6 +11047,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CONST_CV_HAND - !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { - size_t len = ZSTR_LEN(op1_str); - -+ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); - ZVAL_NEW_STR(EX_VAR(opline->result.var), str); -@@ -11036,6 +11057,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CONST_CV_HAND - zend_string_release_ex(op2_str, 0); - } - } else { -+ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); - memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -14644,7 +14668,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_TMPVAR_CONST_HANDL - size_t len = ZSTR_LEN(op1_str); - - if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -- zend_error_noreturn(E_ERROR, "Integer overflow in memory allocation"); -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); - } - str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -14653,6 +14677,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_TMPVAR_CONST_HANDL - zend_string_release_ex(op2_str, 0); - } - } else { -+ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); - memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -15374,6 +15401,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_TMPVAR_CONST_ - !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { - size_t len = ZSTR_LEN(op1_str); - -+ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); - ZVAL_NEW_STR(EX_VAR(opline->result.var), str); -@@ -15381,6 +15411,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_TMPVAR_CONST_ - zend_string_release_ex(op2_str, 0); - } - } else { -+ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); - memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -16067,7 +16100,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_TMPVAR_TMPVAR_HAND - size_t len = ZSTR_LEN(op1_str); - - if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -- zend_error_noreturn(E_ERROR, "Integer overflow in memory allocation"); -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); - } - str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -16076,6 +16109,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_TMPVAR_TMPVAR_HAND - zend_string_release_ex(op2_str, 0); - } - } else { -+ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); - memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -16797,6 +16833,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_TMPVAR_TMPVAR - !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { - size_t len = ZSTR_LEN(op1_str); - -+ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); - ZVAL_NEW_STR(EX_VAR(opline->result.var), str); -@@ -16804,6 +16843,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_TMPVAR_TMPVAR - zend_string_release_ex(op2_str, 0); - } - } else { -+ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); - memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -17744,7 +17786,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_TMPVAR_CV_HANDLER( - size_t len = ZSTR_LEN(op1_str); - - if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -- zend_error_noreturn(E_ERROR, "Integer overflow in memory allocation"); -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); - } - str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -17753,6 +17795,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_TMPVAR_CV_HANDLER( - zend_string_release_ex(op2_str, 0); - } - } else { -+ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); - memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -18112,6 +18157,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_TMPVAR_CV_HAN - !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { - size_t len = ZSTR_LEN(op1_str); - -+ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); - ZVAL_NEW_STR(EX_VAR(opline->result.var), str); -@@ -18119,6 +18167,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_TMPVAR_CV_HAN - zend_string_release_ex(op2_str, 0); - } - } else { -+ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); - memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -39226,7 +39277,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_CV_CONST_HANDLER(Z - size_t len = ZSTR_LEN(op1_str); - - if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -- zend_error_noreturn(E_ERROR, "Integer overflow in memory allocation"); -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); - } - str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -39235,6 +39286,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_CV_CONST_HANDLER(Z - zend_string_release_ex(op2_str, 0); - } - } else { -+ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); - memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -41677,6 +41731,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CV_CONST_HAND - !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { - size_t len = ZSTR_LEN(op1_str); - -+ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); - ZVAL_NEW_STR(EX_VAR(opline->result.var), str); -@@ -41684,6 +41741,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CV_CONST_HAND - zend_string_release_ex(op2_str, 0); - } - } else { -+ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); - memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -42951,7 +43011,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_CV_TMPVAR_HANDLER( - size_t len = ZSTR_LEN(op1_str); - - if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -- zend_error_noreturn(E_ERROR, "Integer overflow in memory allocation"); -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); - } - str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -42960,6 +43020,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_CV_TMPVAR_HANDLER( - zend_string_release_ex(op2_str, 0); - } - } else { -+ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); - memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -45331,6 +45394,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CV_TMPVAR_HAN - !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { - size_t len = ZSTR_LEN(op1_str); - -+ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); - ZVAL_NEW_STR(EX_VAR(opline->result.var), str); -@@ -45338,6 +45404,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CV_TMPVAR_HAN - zend_string_release_ex(op2_str, 0); - } - } else { -+ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); - memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -48150,7 +48219,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_CV_CV_HANDLER(ZEND - size_t len = ZSTR_LEN(op1_str); - - if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -- zend_error_noreturn(E_ERROR, "Integer overflow in memory allocation"); -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); - } - str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -48159,6 +48228,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_CV_CV_HANDLER(ZEND - zend_string_release_ex(op2_str, 0); - } - } else { -+ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); - memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -50629,6 +50701,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CV_CV_HANDLER - !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { - size_t len = ZSTR_LEN(op1_str); - -+ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); - ZVAL_NEW_STR(EX_VAR(opline->result.var), str); -@@ -50636,6 +50711,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CV_CV_HANDLER - zend_string_release_ex(op2_str, 0); - } - } else { -+ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); - memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -diff --git a/ext/session/session.c b/ext/session/session.c -index 3c875296c3a1..0c45b1bb41db 100644 ---- a/ext/session/session.c -+++ b/ext/session/session.c -@@ -3017,7 +3017,7 @@ static int php_session_rfc1867_callback(unsigned int event, void *event_data, vo - if (php_session_rfc1867_orig_callback) { - retval = php_session_rfc1867_orig_callback(event, event_data, extra); - } -- if (!PS(rfc1867_enabled)) { -+ if (!PS(rfc1867_enabled) || true) { - return retval; - } - -diff --git a/main/SAPI.c b/main/SAPI.c -index eea417cedcc3..85d964d21bdb 100644 ---- a/main/SAPI.c -+++ b/main/SAPI.c -@@ -503,18 +503,23 @@ SAPI_API void sapi_deactivate_module(void) - } - if (SG(request_info).auth_user) { - efree(SG(request_info).auth_user); -+ SG(request_info).auth_user = NULL; - } - if (SG(request_info).auth_password) { - efree(SG(request_info).auth_password); -+ SG(request_info).auth_password = NULL; - } - if (SG(request_info).auth_digest) { - efree(SG(request_info).auth_digest); -+ SG(request_info).auth_digest = NULL; - } - if (SG(request_info).content_type_dup) { - efree(SG(request_info).content_type_dup); -+ SG(request_info).content_type_dup = NULL; - } - if (SG(request_info).current_user) { - efree(SG(request_info).current_user); -+ SG(request_info).current_user = NULL; - } - if (sapi_module.deactivate) { - sapi_module.deactivate(); -diff --git a/main/main.c b/main/main.c -index c58ea58bf5ac..48feda4bc7e3 100644 ---- a/main/main.c -+++ b/main/main.c -@@ -1847,6 +1847,8 @@ void php_request_shutdown(void *dummy) - - for (i=0; i -Date: Sun, 18 Oct 2026 20:12:35 +0200 -Subject: [PATCH] Avoid state corruption via bailout - -Minimal mitigation for EOL version. - -Fix GHSA-w8hw-w9fx-j79w (CVE-2026-109618) -Fix GHSA-6wmf-4rv5-p3rp (CVE-2026-109619) - -Co-authored-by: Ilija Tovilo ---- - Zend/zend_API.h | 1 + - Zend/zend_alloc.c | 68 +++++++++----- - Zend/zend_alloc.h | 2 + - Zend/zend_execute_API.c | 15 ++++ - Zend/zend_hash.c | 13 ++- - Zend/zend_hash.h | 1 + - Zend/zend_multiply.h | 4 +- - Zend/zend_strtod.c | 4 +- - Zend/zend_types.h | 26 +++--- - Zend/zend_vm_def.h | 11 ++- - Zend/zend_vm_execute.h | 94 ++++++++++++++++++-- - ext/opcache/ZendAccelerator.c | 5 ++ - ext/opcache/ZendAccelerator.h | 11 ++- - ext/opcache/zend_file_cache.c | 8 ++ - ext/opcache/zend_persist.c | 67 ++++++++++++-- - ext/session/session.c | 2 +- - ext/zend_test/tests/observer_bug81430_2.phpt | 2 - - ext/zend_test/tests/observer_bug81435.phpt | 1 - - ext/zend_test/tests/observer_error_01.phpt | 2 - - main/SAPI.c | 5 ++ - main/main.c | 6 ++ - main/php_variables.c | 8 +- - main/rfc1867.c | 28 ++++-- - 23 files changed, 311 insertions(+), 73 deletions(-) - -diff --git a/Zend/zend_API.h b/Zend/zend_API.h -index 9ed1a3fbabd2..a32b83c0533d 100644 ---- a/Zend/zend_API.h -+++ b/Zend/zend_API.h -@@ -490,6 +490,7 @@ ZEND_API const char *zend_get_type_by_const(int type); - - #define array_init(arg) ZVAL_ARR((arg), zend_new_array(0)) - #define array_init_size(arg, size) ZVAL_ARR((arg), zend_new_array(size)) -+#define array_init_singleton(arg) ZVAL_ARR((arg), zend_new_array_singleton()) - ZEND_API void object_init(zval *arg); - ZEND_API zend_result object_init_ex(zval *arg, zend_class_entry *ce); - ZEND_API zend_result object_and_properties_init(zval *arg, zend_class_entry *ce, HashTable *properties); -diff --git a/Zend/zend_alloc.c b/Zend/zend_alloc.c -index 61792b37c9c5..7f43a7f6df07 100644 ---- a/Zend/zend_alloc.c -+++ b/Zend/zend_alloc.c -@@ -57,6 +57,7 @@ - #include "zend_operators.h" - #include "zend_multiply.h" - #include "zend_bitset.h" -+#include "zend_execute.h" - #include - - #ifdef HAVE_UNISTD_H -@@ -364,7 +365,42 @@ static ZEND_COLD ZEND_NORETURN void zend_mm_panic(const char *message) - #if ZEND_DEBUG && defined(HAVE_KILL) && defined(HAVE_GETPID) - kill(getpid(), SIGSEGV); - #endif -- exit(1); -+ _exit(1); -+} -+ -+ZEND_API ZEND_COLD ZEND_NORETURN void zend_mm_safe_error_ex(const char *format, ...) -+{ -+ zend_string *script_filename = NULL; -+ uint32_t script_lineno = 0; -+ -+ if (zend_is_executing()) { -+ script_filename = zend_get_executed_filename_ex(); -+ script_lineno = zend_get_executed_lineno(); -+ } else if (zend_is_compiling()) { -+ script_filename = zend_get_compiled_filename(); -+ script_lineno = zend_get_compiled_lineno(); -+ } -+ -+ va_list args; -+ va_start(args, format); -+ -+ char buf[1024]; -+ vsnprintf(buf, sizeof(buf), format, args); -+ -+ va_end(args); -+ -+ fprintf(stderr, -+ "\nFatal error: %s in %s on line %d\n", -+ buf, -+ script_filename ? ZSTR_VAL(script_filename) : "Unknown", -+ script_lineno); -+ -+ /* See http://support.microsoft.com/kb/190351 */ -+# ifdef ZEND_WIN32 -+ fflush(stderr); -+# endif -+ -+ _exit(1); - } - - static ZEND_COLD ZEND_NORETURN void zend_mm_safe_error(zend_mm_heap *heap, -@@ -376,22 +412,14 @@ static ZEND_COLD ZEND_NORETURN void zend_mm_safe_error(zend_mm_heap *heap, - #endif - size_t size) - { -+ (void) heap; - -- heap->overflow = 1; -- zend_try { -- zend_error_noreturn(E_ERROR, -- format, -- limit, -+ zend_mm_safe_error_ex(format, limit, - #if ZEND_DEBUG -- filename, -- lineno, -+ filename, -+ lineno, - #endif -- size); -- } zend_catch { -- } zend_end_try(); -- heap->overflow = 0; -- zend_bailout(); -- exit(1); -+ size); - } - - #ifdef _WIN32 -@@ -1356,7 +1384,7 @@ static zend_always_inline void *zend_mm_alloc_heap(zend_mm_heap *heap, size_t si - size = MAX(size, 1); - size = ZEND_MM_ALIGNED_SIZE(size) + ZEND_MM_ALIGNED_SIZE(sizeof(zend_mm_debug_info)); - if (UNEXPECTED(size < real_size)) { -- zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%zu + %zu)", ZEND_MM_ALIGNED_SIZE(real_size), ZEND_MM_ALIGNED_SIZE(sizeof(zend_mm_debug_info))); -+ zend_mm_safe_error_ex("Possible integer overflow in memory allocation (%zu + %zu)", ZEND_MM_ALIGNED_SIZE(real_size), ZEND_MM_ALIGNED_SIZE(sizeof(zend_mm_debug_info))); - return NULL; - } - #endif -@@ -1800,7 +1828,7 @@ static void *zend_mm_alloc_huge(zend_mm_heap *heap, size_t size ZEND_FILE_LINE_D - void *ptr; - - if (UNEXPECTED(new_size < size)) { -- zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%zu + %zu)", size, alignment); -+ zend_mm_safe_error_ex("Possible integer overflow in memory allocation (%zu + %zu)", size, alignment); - } - - #if ZEND_MM_LIMIT -@@ -2660,7 +2688,7 @@ ZEND_API char* ZEND_FASTCALL _estrdup(const char *s ZEND_FILE_LINE_DC ZEND_FILE_ - - length = strlen(s); - if (UNEXPECTED(length + 1 == 0)) { -- zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (1 * %zu + 1)", length); -+ zend_mm_safe_error_ex("Possible integer overflow in memory allocation (1 * %zu + 1)", length); - } - p = (char *) _emalloc(length + 1 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC); - memcpy(p, s, length+1); -@@ -2672,7 +2700,7 @@ ZEND_API char* ZEND_FASTCALL _estrndup(const char *s, size_t length ZEND_FILE_LI - char *p; - - if (UNEXPECTED(length + 1 == 0)) { -- zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (1 * %zu + 1)", length); -+ zend_mm_safe_error_ex("Possible integer overflow in memory allocation (1 * %zu + 1)", length); - } - p = (char *) _emalloc(length + 1 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC); - memcpy(p, s, length); -@@ -2686,7 +2714,7 @@ ZEND_API char* ZEND_FASTCALL zend_strndup(const char *s, size_t length) - char *p; - - if (UNEXPECTED(length + 1 == 0)) { -- zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (1 * %zu + 1)", length); -+ zend_mm_safe_error_ex("Possible integer overflow in memory allocation (1 * %zu + 1)", length); - } - p = (char *) malloc(length + 1); - if (UNEXPECTED(p == NULL)) { -@@ -3084,7 +3112,7 @@ ZEND_API zend_mm_heap *zend_mm_startup_ex(const zend_mm_handlers *handlers, void - static ZEND_COLD ZEND_NORETURN void zend_out_of_memory(void) - { - fprintf(stderr, "Out of memory\n"); -- exit(1); -+ _exit(1); - } - - ZEND_API void * __zend_malloc(size_t len) -diff --git a/Zend/zend_alloc.h b/Zend/zend_alloc.h -index 9603af8a27d3..72becadc7746 100644 ---- a/Zend/zend_alloc.h -+++ b/Zend/zend_alloc.h -@@ -403,6 +403,8 @@ static void apc_init_heap(void) - size_t zend_mm_globals_size(void); - #endif - -+ZEND_API ZEND_COLD ZEND_NORETURN void zend_mm_safe_error_ex(const char *format, ...); -+ - END_EXTERN_C() - - #endif -diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c -index 1e31934f1581..82cea225a8ed 100644 ---- a/Zend/zend_execute_API.c -+++ b/Zend/zend_execute_API.c -@@ -385,6 +385,12 @@ ZEND_API void zend_shutdown_executor_values(bool fast_shutdown) - #endif - } else { - zend_hash_discard(EG(zend_constants), EG(persistent_constants_count)); -+ /* may be used by zend_error_zstr_at before init_executor */ -+ ZVAL_UNDEF(&EG(user_error_handler)); -+ ZVAL_UNDEF(&EG(user_exception_handler)); -+ memset(&EG(user_error_handlers_error_reporting), 0, sizeof(EG(user_error_handlers_error_reporting))); -+ memset(&EG(user_error_handlers), 0, sizeof(EG(user_error_handlers))); -+ memset(&EG(user_exception_handlers), 0, sizeof(EG(user_exception_handlers))); - } - - zend_objects_store_free_object_storage(&EG(objects_store), fast_shutdown); -@@ -406,6 +412,13 @@ void shutdown_executor(void) /* {{{ */ - - zend_shutdown_executor_values(fast_shutdown); - -+ /* may be used by zend_error_zstr_at before init_executor */ -+ EG(record_errors) = false; -+ EG(num_errors) = 0; -+ EG(errors) = NULL; -+ EG(error_handling) = EH_NORMAL; -+ EG(exception) = NULL; -+ - zend_weakrefs_shutdown(); - zend_max_execution_timer_shutdown(); - zend_fiber_shutdown(); -@@ -422,6 +435,8 @@ void shutdown_executor(void) /* {{{ */ - */ - zend_hash_discard(EG(function_table), EG(persistent_functions_count)); - zend_hash_discard(EG(class_table), EG(persistent_classes_count)); -+ EG(objects_store).object_buckets = NULL; -+ EG(objects_store).top = 1; - } else { - zend_vm_stack_destroy(); - -diff --git a/Zend/zend_hash.c b/Zend/zend_hash.c -index b96a95110117..65f31c2b9a21 100644 ---- a/Zend/zend_hash.c -+++ b/Zend/zend_hash.c -@@ -119,7 +119,7 @@ static zend_always_inline uint32_t zend_hash_check_size(uint32_t nSize) - if (nSize <= HT_MIN_SIZE) { - return HT_MIN_SIZE; - } else if (UNEXPECTED(nSize >= HT_MAX_SIZE)) { -- zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%u * %zu + %zu)", nSize, sizeof(Bucket), sizeof(Bucket)); -+ zend_mm_safe_error_ex("Possible integer overflow in memory allocation (%u * %zu + %zu)", nSize, sizeof(Bucket), sizeof(Bucket)); - } - - #ifdef ZEND_WIN32 -@@ -276,6 +276,13 @@ ZEND_API HashTable* ZEND_FASTCALL _zend_new_array_0(void) - return ht; - } - -+ZEND_API HashTable* ZEND_FASTCALL zend_new_array_singleton(void) -+{ -+ HashTable *ht = _zend_new_array_0(); -+ ht->nTableSize = 1; -+ return ht; -+} -+ - ZEND_API HashTable* ZEND_FASTCALL _zend_new_array(uint32_t nSize) - { - HashTable *ht = emalloc(sizeof(HashTable)); -@@ -307,7 +314,7 @@ ZEND_API void ZEND_FASTCALL zend_hash_packed_grow(HashTable *ht) - { - HT_ASSERT_RC1(ht); - if (ht->nTableSize >= HT_MAX_SIZE) { -- zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%u * %zu + %zu)", ht->nTableSize * 2, sizeof(Bucket), sizeof(Bucket)); -+ zend_mm_safe_error_ex("Possible integer overflow in memory allocation (%u * %zu + %zu)", ht->nTableSize * 2, sizeof(Bucket), sizeof(Bucket)); - } - uint32_t newTableSize = ht->nTableSize * 2; - HT_SET_DATA_ADDR(ht, perealloc2(HT_GET_DATA_ADDR(ht), HT_SIZE_EX(newTableSize, HT_MIN_MASK), HT_USED_SIZE(ht), GC_FLAGS(ht) & IS_ARRAY_PERSISTENT)); -@@ -1233,7 +1240,7 @@ static void ZEND_FASTCALL zend_hash_do_resize(HashTable *ht) - pefree(old_data, GC_FLAGS(ht) & IS_ARRAY_PERSISTENT); - zend_hash_rehash(ht); - } else { -- zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%u * %zu + %zu)", ht->nTableSize * 2, sizeof(Bucket) + sizeof(uint32_t), sizeof(Bucket)); -+ zend_mm_safe_error_ex("Possible integer overflow in memory allocation (%u * %zu + %zu)", ht->nTableSize * 2, sizeof(Bucket) + sizeof(uint32_t), sizeof(Bucket)); - } - } - -diff --git a/Zend/zend_hash.h b/Zend/zend_hash.h -index 092682d67713..09a7994d91d5 100644 ---- a/Zend/zend_hash.h -+++ b/Zend/zend_hash.h -@@ -314,6 +314,7 @@ ZEND_API void ZEND_FASTCALL zend_hash_rehash(HashTable *ht); - #endif - - ZEND_API HashTable* ZEND_FASTCALL _zend_new_array_0(void); -+ZEND_API HashTable* ZEND_FASTCALL zend_new_array_singleton(void); - ZEND_API HashTable* ZEND_FASTCALL _zend_new_array(uint32_t size); - ZEND_API HashTable* ZEND_FASTCALL zend_new_pair(zval *val1, zval *val2); - ZEND_API uint32_t zend_array_count(HashTable *ht); -diff --git a/Zend/zend_multiply.h b/Zend/zend_multiply.h -index c6cd472a237b..bfe1b8e88692 100644 ---- a/Zend/zend_multiply.h -+++ b/Zend/zend_multiply.h -@@ -321,7 +321,7 @@ static zend_always_inline size_t zend_safe_address_guarded(size_t nmemb, size_t - size_t ret = zend_safe_address(nmemb, size, offset, &overflow); - - if (UNEXPECTED(overflow)) { -- zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%zu * %zu + %zu)", nmemb, size, offset); -+ zend_mm_safe_error_ex("Possible integer overflow in memory allocation (%zu * %zu + %zu)", nmemb, size, offset); - return 0; - } - return ret; -@@ -334,7 +334,7 @@ static zend_always_inline size_t zend_safe_addmult(size_t nmemb, size_t size, si - size_t ret = zend_safe_address(nmemb, size, offset, &overflow); - - if (UNEXPECTED(overflow)) { -- zend_error_noreturn(E_ERROR, "Possible integer overflow in %s (%zu * %zu + %zu)", message, nmemb, size, offset); -+ zend_mm_safe_error_ex("Possible integer overflow in %s (%zu * %zu + %zu)", message, nmemb, size, offset); - return 0; - } - return ret; -diff --git a/Zend/zend_strtod.c b/Zend/zend_strtod.c -index 3e7f90378ef5..7f72c82f610e 100644 ---- a/Zend/zend_strtod.c -+++ b/Zend/zend_strtod.c -@@ -593,7 +593,7 @@ Balloc - rv = (Bigint *)MALLOC(sizeof(Bigint) + (x-1)*sizeof(ULong)); - if (!rv) { - FREE_DTOA_LOCK(0); -- zend_error_noreturn(E_ERROR, "Balloc() failed to allocate memory"); -+ zend_mm_safe_error_ex("Balloc() failed to allocate memory"); - } - #else - len = (sizeof(Bigint) + (x-1)*sizeof(ULong) + sizeof(double) - 1) -@@ -606,7 +606,7 @@ Balloc - rv = (Bigint*)MALLOC(len*sizeof(double)); - if (!rv) { - FREE_DTOA_LOCK(0); -- zend_error_noreturn(E_ERROR, "Balloc() failed to allocate memory"); -+ zend_mm_safe_error_ex("Balloc() failed to allocate memory"); - } - #endif - rv->k = k; -diff --git a/Zend/zend_types.h b/Zend/zend_types.h -index 5bc47dd31934..ab28b0fa163b 100644 ---- a/Zend/zend_types.h -+++ b/Zend/zend_types.h -@@ -448,17 +448,21 @@ struct _zend_array { - # define HT_HASH_RESET(ht) do { \ - char *p = (char*)&HT_HASH(ht, (ht)->nTableMask); \ - size_t size = HT_HASH_SIZE((ht)->nTableMask); \ -- __m128i xmm0 = _mm_setzero_si128(); \ -- xmm0 = _mm_cmpeq_epi8(xmm0, xmm0); \ -- ZEND_ASSERT(size >= 64 && ((size & 0x3f) == 0)); \ -- do { \ -- _mm_storeu_si128((__m128i*)p, xmm0); \ -- _mm_storeu_si128((__m128i*)(p+16), xmm0); \ -- _mm_storeu_si128((__m128i*)(p+32), xmm0); \ -- _mm_storeu_si128((__m128i*)(p+48), xmm0); \ -- p += 64; \ -- size -= 64; \ -- } while (size != 0); \ -+ if (UNEXPECTED(size < 64)) { \ -+ memset(p, HT_INVALID_IDX, size); \ -+ } else { \ -+ __m128i xmm0 = _mm_setzero_si128(); \ -+ xmm0 = _mm_cmpeq_epi8(xmm0, xmm0); \ -+ ZEND_ASSERT(size >= 64 && ((size & 0x3f) == 0)); \ -+ do { \ -+ _mm_storeu_si128((__m128i*)p, xmm0); \ -+ _mm_storeu_si128((__m128i*)(p+16), xmm0); \ -+ _mm_storeu_si128((__m128i*)(p+32), xmm0); \ -+ _mm_storeu_si128((__m128i*)(p+48), xmm0); \ -+ p += 64; \ -+ size -= 64; \ -+ } while (size != 0); \ -+ } \ - } while (0) - #else - # define HT_HASH_RESET(ht) \ -diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h -index a6f86a9eab6f..ad893ebfb5c6 100644 ---- a/Zend/zend_vm_def.h -+++ b/Zend/zend_vm_def.h -@@ -408,7 +408,7 @@ ZEND_VM_HANDLER(8, ZEND_CONCAT, CONST|TMPVAR|CV, CONST|TMPVAR|CV, SPEC(NO_CONST_ - size_t len = ZSTR_LEN(op1_str); - - if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -- zend_error_noreturn(E_ERROR, "Integer overflow in memory allocation"); -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); - } - str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -417,6 +417,9 @@ ZEND_VM_HANDLER(8, ZEND_CONCAT, CONST|TMPVAR|CV, CONST|TMPVAR|CV, SPEC(NO_CONST_ - zend_string_release_ex(op2_str, 0); - } - } else { -+ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); - memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -3183,6 +3186,9 @@ ZEND_VM_COLD_CONSTCONST_HANDLER(53, ZEND_FAST_CONCAT, CONST|TMPVAR|CV, CONST|TMP - !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { - size_t len = ZSTR_LEN(op1_str); - -+ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); - ZVAL_NEW_STR(EX_VAR(opline->result.var), str); -@@ -3190,6 +3196,9 @@ ZEND_VM_COLD_CONSTCONST_HANDLER(53, ZEND_FAST_CONCAT, CONST|TMPVAR|CV, CONST|TMP - zend_string_release_ex(op2_str, 0); - } - } else { -+ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); - memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h -index 5ee1c2c94daf..dc78ba4a08d0 100644 ---- a/Zend/zend_vm_execute.h -+++ b/Zend/zend_vm_execute.h -@@ -6549,6 +6549,9 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_ - !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { - size_t len = ZSTR_LEN(op1_str); - -+ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); - ZVAL_NEW_STR(EX_VAR(opline->result.var), str); -@@ -6556,6 +6559,9 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_ - zend_string_release_ex(op2_str, 0); - } - } else { -+ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); - memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -8456,7 +8462,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_CONST_TMPVAR_HANDL - size_t len = ZSTR_LEN(op1_str); - - if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -- zend_error_noreturn(E_ERROR, "Integer overflow in memory allocation"); -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); - } - str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -8465,6 +8471,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_CONST_TMPVAR_HANDL - zend_string_release_ex(op2_str, 0); - } - } else { -+ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); - memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -8872,6 +8881,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CONST_TMPVAR_ - !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { - size_t len = ZSTR_LEN(op1_str); - -+ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); - ZVAL_NEW_STR(EX_VAR(opline->result.var), str); -@@ -8879,6 +8891,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CONST_TMPVAR_ - zend_string_release_ex(op2_str, 0); - } - } else { -+ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); - memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -10821,7 +10836,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_CONST_CV_HANDLER(Z - size_t len = ZSTR_LEN(op1_str); - - if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -- zend_error_noreturn(E_ERROR, "Integer overflow in memory allocation"); -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); - } - str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -10830,6 +10845,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_CONST_CV_HANDLER(Z - zend_string_release_ex(op2_str, 0); - } - } else { -+ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); - memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -11237,6 +11255,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CONST_CV_HAND - !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { - size_t len = ZSTR_LEN(op1_str); - -+ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); - ZVAL_NEW_STR(EX_VAR(opline->result.var), str); -@@ -11244,6 +11265,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CONST_CV_HAND - zend_string_release_ex(op2_str, 0); - } - } else { -+ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); - memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -14866,7 +14890,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_TMPVAR_CONST_HANDL - size_t len = ZSTR_LEN(op1_str); - - if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -- zend_error_noreturn(E_ERROR, "Integer overflow in memory allocation"); -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); - } - str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -14875,6 +14899,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_TMPVAR_CONST_HANDL - zend_string_release_ex(op2_str, 0); - } - } else { -+ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); - memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -15596,6 +15623,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_TMPVAR_CONST_ - !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { - size_t len = ZSTR_LEN(op1_str); - -+ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); - ZVAL_NEW_STR(EX_VAR(opline->result.var), str); -@@ -15603,6 +15633,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_TMPVAR_CONST_ - zend_string_release_ex(op2_str, 0); - } - } else { -+ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); - memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -16295,7 +16328,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_TMPVAR_TMPVAR_HAND - size_t len = ZSTR_LEN(op1_str); - - if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -- zend_error_noreturn(E_ERROR, "Integer overflow in memory allocation"); -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); - } - str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -16304,6 +16337,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_TMPVAR_TMPVAR_HAND - zend_string_release_ex(op2_str, 0); - } - } else { -+ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); - memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -17025,6 +17061,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_TMPVAR_TMPVAR - !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { - size_t len = ZSTR_LEN(op1_str); - -+ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); - ZVAL_NEW_STR(EX_VAR(opline->result.var), str); -@@ -17032,6 +17071,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_TMPVAR_TMPVAR - zend_string_release_ex(op2_str, 0); - } - } else { -+ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); - memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -17981,7 +18023,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_TMPVAR_CV_HANDLER( - size_t len = ZSTR_LEN(op1_str); - - if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -- zend_error_noreturn(E_ERROR, "Integer overflow in memory allocation"); -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); - } - str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -17990,6 +18032,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_TMPVAR_CV_HANDLER( - zend_string_release_ex(op2_str, 0); - } - } else { -+ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); - memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -18349,6 +18394,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_TMPVAR_CV_HAN - !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { - size_t len = ZSTR_LEN(op1_str); - -+ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); - ZVAL_NEW_STR(EX_VAR(opline->result.var), str); -@@ -18356,6 +18404,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_TMPVAR_CV_HAN - zend_string_release_ex(op2_str, 0); - } - } else { -+ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); - memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -39651,7 +39702,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_CV_CONST_HANDLER(Z - size_t len = ZSTR_LEN(op1_str); - - if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -- zend_error_noreturn(E_ERROR, "Integer overflow in memory allocation"); -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); - } - str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -39660,6 +39711,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_CV_CONST_HANDLER(Z - zend_string_release_ex(op2_str, 0); - } - } else { -+ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); - memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -42142,6 +42196,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CV_CONST_HAND - !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { - size_t len = ZSTR_LEN(op1_str); - -+ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); - ZVAL_NEW_STR(EX_VAR(opline->result.var), str); -@@ -42149,6 +42206,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CV_CONST_HAND - zend_string_release_ex(op2_str, 0); - } - } else { -+ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); - memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -43460,7 +43520,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_CV_TMPVAR_HANDLER( - size_t len = ZSTR_LEN(op1_str); - - if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -- zend_error_noreturn(E_ERROR, "Integer overflow in memory allocation"); -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); - } - str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -43469,6 +43529,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_CV_TMPVAR_HANDLER( - zend_string_release_ex(op2_str, 0); - } - } else { -+ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); - memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -45880,6 +45943,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CV_TMPVAR_HAN - !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { - size_t len = ZSTR_LEN(op1_str); - -+ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); - ZVAL_NEW_STR(EX_VAR(opline->result.var), str); -@@ -45887,6 +45953,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CV_TMPVAR_HAN - zend_string_release_ex(op2_str, 0); - } - } else { -+ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); - memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -48757,7 +48826,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_CV_CV_HANDLER(ZEND - size_t len = ZSTR_LEN(op1_str); - - if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -- zend_error_noreturn(E_ERROR, "Integer overflow in memory allocation"); -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); - } - str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -48766,6 +48835,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_CV_CV_HANDLER(ZEND - zend_string_release_ex(op2_str, 0); - } - } else { -+ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); - memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -@@ -51276,6 +51348,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CV_CV_HANDLER - !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { - size_t len = ZSTR_LEN(op1_str); - -+ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); - ZVAL_NEW_STR(EX_VAR(opline->result.var), str); -@@ -51283,6 +51358,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CV_CV_HANDLER - zend_string_release_ex(op2_str, 0); - } - } else { -+ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { -+ zend_mm_safe_error_ex("Integer overflow in memory allocation"); -+ } - str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); - memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); - memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); -diff --git a/ext/opcache/ZendAccelerator.c b/ext/opcache/ZendAccelerator.c -index 530620f6259f..e030b4413193 100644 ---- a/ext/opcache/ZendAccelerator.c -+++ b/ext/opcache/ZendAccelerator.c -@@ -2410,6 +2410,7 @@ static zend_class_entry* zend_accel_inheritance_cache_add(zend_class_entry *ce, - } - - zend_map_ptr_extend(ZCSG(map_ptr_last)); -+ zend_accel_pending_ce_cache_begin(); - - #if ZEND_MM_ALIGNMENT < 8 - /* Align to 8-byte boundary */ -@@ -2456,6 +2457,7 @@ static zend_class_entry* zend_accel_inheritance_cache_add(zend_class_entry *ce, - EG(errors) = NULL; - - ZCSG(map_ptr_last) = CG(map_ptr_last); -+ zend_accel_pending_ce_cache_commit(); - - zend_shared_alloc_destroy_xlat_table(); - -@@ -2780,6 +2782,9 @@ zend_result accel_post_deactivate(void) - ZCG(cwd) = NULL; - } - -+ /* A persist window left through a bailout never published its slots */ -+ zend_accel_pending_ce_cache_discard(); -+ - if (!ZCG(enabled) || !accel_startup_ok) { - return SUCCESS; - } -diff --git a/ext/opcache/ZendAccelerator.h b/ext/opcache/ZendAccelerator.h -index de5ec45de72c..72d3a239342b 100644 ---- a/ext/opcache/ZendAccelerator.h -+++ b/ext/opcache/ZendAccelerator.h -@@ -225,6 +225,12 @@ typedef struct _zend_accel_globals { - /* preallocated buffer for keys */ - zend_string key; - char _key[MAXPATHLEN * 8]; -+ -+ /* CE cache slots allocated during the current persist window, keyed by the -+ * address of the shared class name string. They are written into the -+ * strings by zend_accel_pending_ce_cache_commit() once ZCSG(map_ptr_last) -+ * covers them. NULL outside a persist window. */ -+ HashTable *pending_ce_cache; - } zend_accel_globals; - - typedef struct _zend_string_table { -@@ -322,7 +328,10 @@ zend_op_array *persistent_compile_file(zend_file_handle *file_handle, int type); - - zend_string* ZEND_FASTCALL accel_new_interned_string(zend_string *str); - --uint32_t zend_accel_get_class_name_map_ptr(zend_string *type_name); -+void zend_accel_get_class_name_map_ptr(zend_string *type_name); -+void zend_accel_pending_ce_cache_begin(void); -+void zend_accel_pending_ce_cache_commit(void); -+void zend_accel_pending_ce_cache_discard(void); - - /* memory write protection */ - #define SHM_PROTECT() \ -diff --git a/ext/opcache/zend_file_cache.c b/ext/opcache/zend_file_cache.c -index 7b4b4cbb1211..f1b1da2baa78 100644 ---- a/ext/opcache/zend_file_cache.c -+++ b/ext/opcache/zend_file_cache.c -@@ -1696,6 +1696,7 @@ zend_persistent_script *zend_file_cache_script_load(zend_file_handle *file_handl - int cache_it = 1; - unsigned int actual_checksum; - int ok; -+ size_t orig_map_ptr_last = 0; - - if (!full_path) { - return NULL; -@@ -1831,6 +1832,8 @@ zend_persistent_script *zend_file_cache_script_load(zend_file_handle *file_handl - } - memcpy(buf, mem, info.mem_size); - zend_map_ptr_extend(ZCSG(map_ptr_last)); -+ orig_map_ptr_last = CG(map_ptr_last); -+ zend_accel_pending_ce_cache_begin(); - } else { - use_process_mem: - buf = mem; -@@ -1849,6 +1852,10 @@ zend_persistent_script *zend_file_cache_script_load(zend_file_handle *file_handl - } zend_end_try(); - if (!ok) { - if (cache_it) { -+ /* The slots allocated by the failed unserialization are referenced -+ * only by the abandoned buffer, so they can be reclaimed. */ -+ zend_accel_pending_ce_cache_discard(); -+ CG(map_ptr_last) = orig_map_ptr_last; - zend_shared_alloc_unlock(); - goto use_process_mem; - } else { -@@ -1862,6 +1869,7 @@ zend_persistent_script *zend_file_cache_script_load(zend_file_handle *file_handl - - if (cache_it) { - ZCSG(map_ptr_last) = CG(map_ptr_last); -+ zend_accel_pending_ce_cache_commit(); - script->dynamic_members.checksum = zend_accel_script_checksum(script); - script->dynamic_members.last_used = ZCG(request_time); - -diff --git a/ext/opcache/zend_persist.c b/ext/opcache/zend_persist.c -index 49dfea34e33e..4ff93a12b33e 100644 ---- a/ext/opcache/zend_persist.c -+++ b/ext/opcache/zend_persist.c -@@ -299,31 +299,78 @@ static HashTable *zend_persist_attributes(HashTable *attributes) - return ptr; - } - --uint32_t zend_accel_get_class_name_map_ptr(zend_string *type_name) -+/* We delay the publishing of CE cache slots until after ZCSG(map_ptr_last) is -+ * published. -+ * CE cache slots stored in interned strings are immediately visible to other -+ * processes, so if we fail to update ZCSG(map_ptr_last) after publishing a -+ * slot (due to a bailout/exit), that slot may be re-allocated for something -+ * else by other processes. */ -+void zend_accel_pending_ce_cache_begin(void) -+{ -+ ZEND_ASSERT(ZCG(locked)); -+ -+ /* A persist window left through a bailout caught by the caller (e.g. -+ * opcache_compile_file()) never published its slots. Drop them. */ -+ zend_accel_pending_ce_cache_discard(); -+ -+ ZCG(pending_ce_cache) = emalloc(sizeof(HashTable)); -+ zend_hash_init(ZCG(pending_ce_cache), 8, NULL, NULL, 0); -+} -+ -+void zend_accel_pending_ce_cache_commit(void) -+{ -+ ZEND_ASSERT(ZCG(pending_ce_cache)); -+ /* Every pending slot must be covered by ZCSG(map_ptr_last) */ -+ ZEND_ASSERT(ZCSG(map_ptr_last) == CG(map_ptr_last)); -+ -+ ZEND_HASH_FOREACH_NUM_KEY_VAL(ZCG(pending_ce_cache), zend_ulong h, zval *zv) { -+ zend_string *type_name = (zend_string*)(uintptr_t)h; -+ -+ ZEND_ASSERT(!ZSTR_HAS_CE_CACHE(type_name)); -+ GC_SET_REFCOUNT(type_name, (uint32_t)Z_LVAL_P(zv)); -+ GC_ADD_FLAGS(type_name, IS_STR_CLASS_NAME_MAP_PTR); -+ } ZEND_HASH_FOREACH_END(); -+ -+ zend_accel_pending_ce_cache_discard(); -+} -+ -+void zend_accel_pending_ce_cache_discard(void) -+{ -+ if (ZCG(pending_ce_cache)) { -+ zend_hash_destroy(ZCG(pending_ce_cache)); -+ efree(ZCG(pending_ce_cache)); -+ ZCG(pending_ce_cache) = NULL; -+ } -+} -+ -+void zend_accel_get_class_name_map_ptr(zend_string *type_name) - { - uint32_t ret; -+ zval *slot; - - if (zend_string_equals_literal_ci(type_name, "self") || - zend_string_equals_literal_ci(type_name, "parent")) { -- return 0; -+ return; - } - - /* We use type.name.gc.refcount to keep map_ptr of corresponding type */ - if (ZSTR_HAS_CE_CACHE(type_name)) { -- return GC_REFCOUNT(type_name); -+ return; - } - - if ((GC_FLAGS(type_name) & GC_IMMUTABLE) - && (GC_FLAGS(type_name) & IS_STR_PERMANENT)) { -+ ZEND_ASSERT(ZCG(pending_ce_cache) && "Must be called inside a persist window"); -+ slot = zend_hash_index_lookup(ZCG(pending_ce_cache), (zend_ulong)(uintptr_t)type_name); -+ if (Z_TYPE_P(slot) != IS_NULL) { -+ /* Already allocated earlier in this window */ -+ return; -+ } - do { - ret = ZEND_MAP_PTR_NEW_OFFSET(); - } while (ret <= 2); -- GC_SET_REFCOUNT(type_name, ret); -- GC_ADD_FLAGS(type_name, IS_STR_CLASS_NAME_MAP_PTR); -- return ret; -+ ZVAL_LONG(slot, ret); - } -- -- return 0; - } - - static HashTable *zend_persist_backed_enum_table(HashTable *backed_enum_table) -@@ -1312,6 +1359,9 @@ zend_persistent_script *zend_accel_script_persist(zend_persistent_script *script - #endif - - zend_map_ptr_extend(ZCSG(map_ptr_last)); -+ if (for_shm) { -+ zend_accel_pending_ce_cache_begin(); -+ } - - zend_accel_persist_class_table(&script->script.class_table); - zend_hash_persist(&script->script.function_table); -@@ -1336,6 +1386,7 @@ zend_persistent_script *zend_accel_script_persist(zend_persistent_script *script - - if (for_shm) { - ZCSG(map_ptr_last) = CG(map_ptr_last); -+ zend_accel_pending_ce_cache_commit(); - } - - #ifdef HAVE_JIT -diff --git a/ext/session/session.c b/ext/session/session.c -index 114df24b4649..d72ae27b4481 100644 ---- a/ext/session/session.c -+++ b/ext/session/session.c -@@ -3000,7 +3000,7 @@ static int php_session_rfc1867_callback(unsigned int event, void *event_data, vo - if (php_session_rfc1867_orig_callback) { - retval = php_session_rfc1867_orig_callback(event, event_data, extra); - } -- if (!PS(rfc1867_enabled)) { -+ if (!PS(rfc1867_enabled) || true) { - return retval; - } - -diff --git a/ext/zend_test/tests/observer_bug81430_2.phpt b/ext/zend_test/tests/observer_bug81430_2.phpt -index 90e0fa5ce015..2cdbca9a7029 100644 ---- a/ext/zend_test/tests/observer_bug81430_2.phpt -+++ b/ext/zend_test/tests/observer_bug81430_2.phpt -@@ -30,5 +30,3 @@ call_user_func([$r->getAttributes(A::class)[0], 'newInstance']); - - - Fatal error: Allowed memory size of %d bytes exhausted %s in %s on line %d -- -- -diff --git a/ext/zend_test/tests/observer_bug81435.phpt b/ext/zend_test/tests/observer_bug81435.phpt -index 7b927e55fb19..e435292da0bd 100644 ---- a/ext/zend_test/tests/observer_bug81435.phpt -+++ b/ext/zend_test/tests/observer_bug81435.phpt -@@ -45,4 +45,3 @@ a(); - - - Fatal error: Allowed memory size of 20971520 bytes exhausted %s in %s on line %d -- -diff --git a/ext/zend_test/tests/observer_error_01.phpt b/ext/zend_test/tests/observer_error_01.phpt -index 10b1e569b0fa..70a761016a8e 100644 ---- a/ext/zend_test/tests/observer_error_01.phpt -+++ b/ext/zend_test/tests/observer_error_01.phpt -@@ -26,5 +26,3 @@ echo 'You should not see this.'; - - - Fatal error: Allowed memory size of 2097152 bytes exhausted%s(tried to allocate %d bytes) in %s on line %d -- -- -diff --git a/main/SAPI.c b/main/SAPI.c -index 561cf6d598c6..656418a08e54 100644 ---- a/main/SAPI.c -+++ b/main/SAPI.c -@@ -507,18 +507,23 @@ SAPI_API void sapi_deactivate_module(void) - } - if (SG(request_info).auth_user) { - efree(SG(request_info).auth_user); -+ SG(request_info).auth_user = NULL; - } - if (SG(request_info).auth_password) { - efree(SG(request_info).auth_password); -+ SG(request_info).auth_password = NULL; - } - if (SG(request_info).auth_digest) { - efree(SG(request_info).auth_digest); -+ SG(request_info).auth_digest = NULL; - } - if (SG(request_info).content_type_dup) { - efree(SG(request_info).content_type_dup); -+ SG(request_info).content_type_dup = NULL; - } - if (SG(request_info).current_user) { - efree(SG(request_info).current_user); -+ SG(request_info).current_user = NULL; - } - if (sapi_module.deactivate) { - sapi_module.deactivate(); -diff --git a/main/main.c b/main/main.c -index 9c62aa914eb0..b9994ccf9d24 100644 ---- a/main/main.c -+++ b/main/main.c -@@ -1850,6 +1850,8 @@ void php_request_shutdown(void *dummy) - - for (i=0; i isset($_FILES['document']['tmp_name']) && is_uploaded_file($_FILES['document']['tmp_name']) ? file_get_contents($_FILES['document']['tmp_name']) : null, 'nested_upload' => isset($_FILES['uploads']['tmp_name']['document']) && is_uploaded_file($_FILES['uploads']['tmp_name']['document']) ? file_get_contents($_FILES['uploads']['tmp_name']['document']) : null, 'session' => $session, + 'save_path' => ini_get('session.save_path'), 'progress_enabled' => ini_get('session.upload_progress.enabled'), 'progress_cleanup' => ini_get('session.upload_progress.cleanup'), 'multipart_limit' => ini_get('max_multipart_body_parts'), diff --git a/runtime/security/verify.php b/runtime/security/verify.php index c5225bb..d6aa95c 100644 --- a/runtime/security/verify.php +++ b/runtime/security/verify.php @@ -82,7 +82,6 @@ function cleanupMarkers(string $prefix, bool $expected): void php_admin_value[memory_limit] = 32M php_admin_flag[log_errors] = on php_admin_flag[display_errors] = off -php_admin_value[session.save_path] = /tmp/ymir-security php_admin_flag[session.upload_progress.enabled] = on php_admin_flag[session.upload_progress.cleanup] = off php_admin_value[session.upload_progress.freq] = 1 @@ -100,6 +99,11 @@ function cleanupMarkers(string $prefix, bool $expected): void $masterPid = $process->getPid(); $tests = [ + 'native default session storage persists data' => function () use ($initial): void { + check('' === ini_get('session.save_path') && '' === $initial['save_path'], 'CLI/FPM default session.save_path changed from the system temp directory'); + $file = sys_get_temp_dir().'/sess_ymir-security'; + check(is_file($file) && str_contains((string) file_get_contents($file), 'preserved'), 'Session data was not persisted in the default save path'); + }, 'normal and nested multipart uploads' => function () use ($fpm, $workerPid): void { $result = data(request($fpm, '', ['title' => 'normal', 'nested[a][b]' => 'deep', 'nested[a][c]' => 'sibling', 'items[]' => 'item'], ['document' => '/tmp/ymir-security/upload.txt', 'uploads[document]' => '/tmp/ymir-security/upload.txt'])); check(['title' => 'normal', 'nested' => ['a' => ['b' => 'deep', 'c' => 'sibling']], 'items' => ['item']] === $result['post'], 'Multipart fields/nesting changed'); diff --git a/runtime/shared/sury-defaults.ini b/runtime/shared/sury-defaults.ini new file mode 100644 index 0000000..ebdc290 --- /dev/null +++ b/runtime/shared/sury-defaults.ini @@ -0,0 +1,5 @@ +; The Sury source packages compile Debian defaults into PHP 7.2 and 7.3. +; Restore the upstream defaults that the previous runtimes shipped with. +; An empty session.save_path makes file sessions use the system temporary directory (/tmp on Lambda). +include_path = ".:/opt/ymir/lib/php" +session.save_path = "" diff --git a/runtime/sources/README.md b/runtime/sources/README.md new file mode 100644 index 0000000..a2d089b --- /dev/null +++ b/runtime/sources/README.md @@ -0,0 +1,119 @@ +# Vendor-maintained legacy PHP sources + +Ymir consumes complete upstream/vendor source inputs for CVE-2026-109618 +and CVE-2026-109619. **Do not maintain a Ymir patch set, cherry-pick a subset +of distro patches, or modify vendor C/header contents to make a build pass.** +If a vendor source cannot meet the Lambda contracts through normal build +and runtime configuration, stop for a platform/support decision. + +## PHP-team source snapshots: 7.4, 8.0, 8.1 + +The [PHP security announcement](https://www.php.net/archive/2026.php) links +these exceptional source-backport branches. Dockerfiles consume full-commit +archives and verify their pinned SHA-256 before extraction: + +| PHP family | Official source commit | Compiled version | +| --- | --- | --- | +| 7.4 | [`712e60f9edfd03f0960fc4fc3c2c375f42b90aa2`](https://github.com/php/php-src/commit/712e60f9edfd03f0960fc4fc3c2c375f42b90aa2) | `7.4.34-dev` | +| 8.0 | [`82f8f31b16a035c1b67cc253e79f7cc288f4cc20`](https://github.com/php/php-src/commit/82f8f31b16a035c1b67cc253e79f7cc288f4cc20) | `8.0.30` | +| 8.1 | [`1d7dec178a094e6e75b229ce22754045f8c6070a`](https://github.com/php/php-src/commit/1d7dec178a094e6e75b229ce22754045f8c6070a) | `8.1.34` | + +Archive URL: `https://github.com/php/php-src/archive/.tar.gz`. +These are complete vendor trees, not release tarballs with locally applied +patches. Their missing parsers/lexers are generated by the upstream build +using build-only Bison/re2c. Preserve the vendor's real version metadata; +7.4's development banner must not be relabeled as 7.4.33. + +During preparation, each downloaded snapshot was compared with `git archive` +of the exact commit, and all three commit signatures verified against +Ilija Tovilo's key, fingerprint `259299AD4C7E1F40DE1302FF115CEA7A713E12E9`. +The key came from GitHub HTTPS, not an independent web-of-trust check. +The archive checksums enforced by Docker are observed pins, not signed +php.net release checksums. GitHub may regenerate compression bytes; a +checksum mismatch must fail closed and be investigated, never auto-accepted. + +## PEAR bootstrap for the Git snapshots + +The PHP Git snapshots omit the release-bundled PEAR installer. For 7.4, +8.0, and 8.1, the build fetches the unchanged upstream +[`install-pear-nozlib.phar`](https://raw.githubusercontent.com/pear/pearweb_phars/72aa5f771f56aaf826641b21159453f993e44450/install-pear-nozlib.phar) +from PEAR commit `72aa5f771f56aaf826641b21159453f993e44450`, with SHA-256 +`a71349da29f1a6e3f0792695b167e582375a93c70c0e9d35e7c4675697c5f039`. +The checksum must pass before the file is placed in the vendor installer's +expected path or executed by normal `make install`. No floating `master` +bootstrap or PHAR copied from an unrelated PHP release is used. + +## Complete Sury source packages: 7.2, 7.3 + +The [Sury PHP repository](https://packages.sury.org/php/) publishes Debian +`3.0 (quilt)` source packages. Its `orig` archives and packaging Git +checkouts are **not already-backported trees**. A build-only Debian stage +uses the format's native `dpkg-source -x` preparation to apply the vendor's +**complete** ordered series, unchanged: + +| PHP family | Pinned package revision | Vendor packaging commit | Series | +| --- | --- | --- | ---: | +| 7.2 | `7.2.34-66+0~20261021.122+debian13~1.gbpe0bcd4` | [`e0bcd488d9f8da024d9e1a254113539a846cac6d`](https://salsa.debian.org/php-team/php/-/tree/e0bcd488d9f8da024d9e1a254113539a846cac6d) | 159 | +| 7.3 | `7.3.33-35+0~20261021.144+debian13~1.gbpecf76f` | [`ecf76f6726bee03657a2c608240685732312fe54`](https://salsa.debian.org/php-team/php/-/tree/ecf76f6726bee03657a2c608240685732312fe54) | 139 | + +The Dockerfiles pin and verify the complete source file set, including the +`.dsc`, original archive, Debian archive, and the 7.3 upstream signature +file. They do not select patches or substitute pristine-source files. +Generated build preparation follows the vendor's own recipes. Compilation +and final Lambda images remain Amazon Linux 2023; Debian supplies source +preparation tools, not customer runtime binaries. + +The package inputs were authenticated on 2026-10-22 through: + +1. Sury's `InRelease`, signed by key + `15058500A0235D97F5D10063B188E2B695BD4743`. +2. Its SHA-256 entry for `main/source/Sources.xz`. +3. The source index's hashes of each package descriptor and archive. + +The historical key, signed release, and source index are retained under +`provenance/`. Both `.dsc` files are unsigned; do not claim descriptor +signature verification. The trust anchor came from Sury HTTPS, not an +independent identity check. Retained metadata proves pinned bytes, not +current repository freshness or a vendor support guarantee. + +```sh +gpgv --keyring "$PWD/runtime/sources/provenance/sury-keyring.gpg" \ + runtime/sources/provenance/sury-trixie-InRelease +``` + +Sury's complete source includes Debian defaults for sessions, include/PEAR +paths, and extension/header layout. Preserve Ymir's existing Lambda behavior +with supported build/make settings and runtime INI configuration, not by +removing distro patches. The build stage supplies the vendor's own `shtool` +and maps its aclocal/libtool helper paths to native AL2023 files. The pinned +vendor `phpize` probes missing Debian `dpkg` tools only to choose an aux +pathname; its fallback is mapped to AL2023's actual libtool build-aux +location. The missing-tool diagnostics are not suppressed, no commands are +stubbed, and no vendor script is edited. If future sources require other +`dpkg` behavior, reevaluate the integration rather than faking package data. +None of these build-only helper files enters the final layer. + +Optional Sury telemetry is not enabled by the current build flags: do not +define `TELEMETRY_HOST` or import distro binary build flags without a +separate privacy/startup review. + +## Verification and release boundary + +`runtime/test-image.sh ` checks the actual final image, +including bounded legacy mitigation/lifecycle regressions. Both amd64 and +arm64 must pass; source compilation or unchanged API identifiers alone do +not establish extension or Lambda compatibility. These checks do not prove +comprehensive exploit prevention or coverage of every historical CVE. + +The legacy mitigations terminate PHP immediately on OOM (exit 1, bypassing +shutdown callbacks/destructors), disable session upload-progress tracking, +and change some multipart handling. Do not introduce automatic application +retries that could repeat side effects. These remain EOL PHP versions; +backport availability is not resumed upstream support or an SLA. + +This work does not authorize merging, releasing, publishing images/layers, +or updating the platform's layer catalog. A later approved rollout needs +zip redeployment or a rebuilt/redeployed container base (including pinned +digests). Existing deployments are not patched retroactively. Preserve +recovery artifacts, but recognize that reverting to unpatched sources or +artifacts restores exposure; prefer a forward fix. diff --git a/runtime/patches/provenance/sury-keyring.gpg b/runtime/sources/provenance/sury-keyring.gpg similarity index 100% rename from runtime/patches/provenance/sury-keyring.gpg rename to runtime/sources/provenance/sury-keyring.gpg diff --git a/runtime/patches/provenance/sury-trixie-InRelease b/runtime/sources/provenance/sury-trixie-InRelease similarity index 100% rename from runtime/patches/provenance/sury-trixie-InRelease rename to runtime/sources/provenance/sury-trixie-InRelease diff --git a/runtime/patches/provenance/sury-trixie-Sources.xz b/runtime/sources/provenance/sury-trixie-Sources.xz similarity index 100% rename from runtime/patches/provenance/sury-trixie-Sources.xz rename to runtime/sources/provenance/sury-trixie-Sources.xz diff --git a/runtime/test-image.sh b/runtime/test-image.sh index f7eef82..ba91f5e 100755 --- a/runtime/test-image.sh +++ b/runtime/test-image.sh @@ -111,9 +111,17 @@ if [ -z "$EXT_DIR" ]; then echo " [FAIL] Could not determine extension_dir" FAILED=1 else + if ! [[ "$EXT_DIR" =~ ^/opt/ymir/lib/php/extensions/no-debug-non-zts-[0-9]{8}$ ]]; then + echo " [FAIL] extension_dir changed: $EXT_DIR" + FAILED=1 + fi if docker run --rm --platform "$PLATFORM" --entrypoint /bin/sh "$IMAGE" -c "[ -d $EXT_DIR ]"; then echo " [OK] Extension directory exists: $EXT_DIR" - for ext in "pdo_mysql.so" "pdo_pgsql.so" "pgsql.so"; do + INI_CONTENT=$(docker run --rm --platform "$PLATFORM" --entrypoint /bin/sh "$IMAGE" -c "cat /opt/ymir/etc/php/php.ini /opt/ymir/etc/php/conf.d/*.ini 2>/dev/null") || exit 1 + # shortcut: shipped INIs use relative .so names; normalize paths if that format changes. + INI_EXTENSIONS=$(printf '%s\n' "$INI_CONTENT" | sed -nE 's/^[[:space:]]*(zend_)?extension[[:space:]]*=[[:space:]]*"?([^";[:space:]]+)"?.*/\2/p') + if [ -z "$INI_EXTENSIONS" ]; then echo " [FAIL] No extension entries found in shipped INI files"; exit 1; fi + for ext in "pdo_mysql.so" "pdo_pgsql.so" "pgsql.so" $INI_EXTENSIONS; do if docker run --rm --platform "$PLATFORM" --entrypoint /bin/sh "$IMAGE" -c "[ -f $EXT_DIR/$ext ]"; then echo " [OK] Extension file exists: $ext" else @@ -134,6 +142,15 @@ else fi fi +# 5.6 Default paths (empty session.save_path means the system temp directory) +DEFAULT_PATHS=$(docker run --rm --platform "$PLATFORM" -e LD_LIBRARY_PATH="$LAMBDA_LD_PATH" --entrypoint /opt/ymir/bin/php "$IMAGE" -r "echo ini_get('session.save_path'), '|', ini_get('include_path');" 2>/dev/null) +if [ "$DEFAULT_PATHS" = "|.:/opt/ymir/lib/php" ]; then + echo " [OK] Default session.save_path and include_path" +else + echo " [FAIL] Default session.save_path|include_path changed: '$DEFAULT_PATHS'" + FAILED=1 +fi + # 6. Relay Configuration if [ -n "$PHP_VER" ] && [ "$PHP_VER" -ge 70400 ]; then EVICTION_POLICY=$(docker run --rm --platform "$PLATFORM" -e LD_LIBRARY_PATH="$LAMBDA_LD_PATH" --entrypoint /opt/ymir/bin/php "$IMAGE" -r "echo ini_get('relay.eviction_policy');" 2>/dev/null)