Skip to content

JIT bug: composer install sometimes hangs #22086

Closed as duplicate
Closed as duplicate

Description

@ondrejmirtes

Description

composer install sometimes hangs when JIT is on and set to tracing. I created a reproducing repo that shows the problem: https://github.com/ondrejmirtes/composer-hang-repro

Disclaimer: Claude Code helped me create the reproducer. The repo contains two Dockerfiles (with JIT on/off) that shows the difference in behaviour and loop.sh script that runs composer install over and over and shows that it hangs in about 3 % of performed runs.

There are some details in the README but consider them with a grain of salt.

To reproduce the problem in the cloned link repository:

# Build both images (PHP 8.5.6 + Composer 2.9.5)
docker build -t composer-jit-hang  -f Dockerfile.jit  .
docker build -t composer-jit-nojit -f Dockerfile.nojit .

# 1) See the hang with opcache.jit=tracing.
#    loop.sh bootstraps vendor/ on first run (one ~30 s install to bring in
#    Symfony Flex, which has to be loaded as a plugin for the JIT bug to
#    fire), then runs `composer install --dry-run` 200 times. Expect a
#    handful of those runs to be killed at the 15 s deadline — last
#    measurement: 19 hangs in 500 runs.
docker run --rm \
  -v "$PWD":/work \
  composer-jit-hang bash /loop.sh 200

# 2) Same project, same Composer, same PHP, JIT off — zero hangs.
docker run --rm \
  -v "$PWD":/work \
  composer-jit-nojit bash /loop.sh 200

PHP Version

PHP 8.5.6 (cli) (built: May  8 2026 19:23:57) (NTS)
     Copyright (c) The PHP Group
     Built by https://github.com/docker-library/php

Operating System

Debian 13.4

Activity

  1. morrisonlevi commented on Jun 23, 2026

    @morrisonlevi
    Contributor

    Do you know what it's hung in? If you can still reproduce this, can you attach gdb to the process, source the .gdbinit file for PHP 8.5, and run zbacktrace as well as backtrace?

  2. ndossche commented on Oct 6, 2026

    @ndossche
    Member

    Thanks for the reproducer. This is a duplicate of GH-22915, which is fixed in PHP 8.5.10.

    It's this: RuleSetGenerator::addRulesForPackage(), the tracing JIT makes $this->addedMap assume a packed array.
    Once the array is no longer packed, the packed guard fails.
    Depending on timing, this exit sometimes gets blacklisted. The code it then runs to hand back to the interpreter increments the array's refcount before it saves the other live registers. That increment can overwrite the register holding $package->id in %rax.
    The interpreter then re-runs the isset() with garbage data, and returns false. The same packages are re-enqueued over and over and the loop never ends.

    With the official Docker images and your project: 8.5.9 hung in 6 of 500 runs, 8.5.10 in 0 of 500. Please upgrade to 8.5.10 or later.

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

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions