Skip to content

[Bug]: Static PHP 8.5 x86_64 (herd-lite) SIGILL / "Illegal instruction" (exit 132) on CPUs without ADX (e.g. Intel Haswell i7-4790) — GMP built with ADX enabled #1747

Description

@mdahamshi

Platform

macOS

Operating system version

Linux 6.14.8-2-pve (Proxmox), x86_64

System architecture

Intel (x86)

Herd Version

laravel 13

PHP Version

php 8.5.0 (cli), NTS, Nov 20 2025

Bug description

Summary

A prebuilt static PHP 8.5.0 binary from your distribution crashes with SIGILL / Illegal instruction (exit 132) on any CPU that lacks the ADX instruction set — for example an Intel Core i7-4790 (Haswell). The crash is inside GMP 6.3.0's big-number multiplication (mpn_mul_1), which was compiled with ADX (adcx/adox) and BMI2 (mulx) enabled and shipped without a runtime CPUID gate. Haswell has BMI2 but no ADX, so the ADX instruction stream faults.

This is a broad compatibility problem: it will crash on every pre-Broadwell Intel (Sandy Bridge → Haswell) and many older/lower-end AMD parts, on a completely ordinary gmp_mul() call.

Environment

  • Host CPU: Intel Core i7-4790 @ 3.60GHz (Haswell)
    • has: bmi1 bmi2 avx2 sse4_2adx ABSENT
  • OS: Linux 6.14.8-2-pve (Proxmox), x86_64
  • Binary: php 8.5.0 (cli), NTS, x86_64-linux-musl-gcc, static, stripped
    • Built by Beyond Code for php.new, Nov 20 2025
    • GMP 6.3.0 (static), OpenSSL 3.6.0 (static)
  • Thread safety: disabled

Root cause (build-time)

Your static build compiled the bundled GMP with ADX enabled (the shipped object contains adcx/adox), but shipping it that way is only safe if a runtime CPUID check selects the ADX path; otherwise it faults on any non-ADX CPU. The GMP code path here has BMI2+ADX instructions reachable unconditionally on the affected CPUs.

Suggested fix

  • Rebuild GMP for the static PHP distribution without ADX — most simply --disable-assembly (GMP then uses its portable C path), or ensure the compile flags do not enable -madx/-march for the GMP low-level multiply objects.
  • Ideally ensure GMP's runtime CPU detection (its .asm mulx/ADX variants gate on the CPUID ADX bit) is actually being used, rather than a fixed instruction stream.
  • Re-test on a Haswell-class CPU (i7-4xxx / Xeon E3 v3) after rebuilding.

Impact

Any deployment of this static PHP build on hardware older than ADX support (roughly pre-2015 Intel Broadwell and many older AMD CPUs) will crash during ordinary big-number arithmetic (gmp_mul, and any library built on it, e.g. phpseclib BigInteger). This makes the distributed binary unusable on a large class of still-common servers/VMs.


*Separate root-cause report filed with GMP upstream.

Steps to reproduce

Reproducer (self-contained, no external libs)

<?php
$a = gmp_init(str_repeat('12345678901234567890', 40), 10);
$b = gmp_init(str_repeat('98765432109876543210', 40), 10);
$r = gmp_mul($a, $b);
echo gmp_strval($r, 10), "\n";

Run:

/path/to/php repro_gmp.php

Observed:

Illegal instruction
(exit code 132)

The size is chosen to force the multi-limb ADX multiply path; smaller multiplications that stay in a single-limb path may not fault, which is why this can appear intermittent.

Relevant log output

Illegal instruction
(exit code 132)

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions