Skip to content

Fix GH-21267: JIT infinite loop on FETCH_OBJ_R with IS_UNDEF property#21368

Open
iliaal wants to merge 1 commit intophp:masterfrom
iliaal:fix/gh-21267-jit-fetch-obj-undef-loop
Open

Fix GH-21267: JIT infinite loop on FETCH_OBJ_R with IS_UNDEF property#21368
iliaal wants to merge 1 commit intophp:masterfrom
iliaal:fix/gh-21267-jit-fetch-obj-undef-loop

Conversation

@iliaal
Copy link
Contributor

@iliaal iliaal commented Mar 7, 2026

Fixes #21267

When JIT compiles a side trace for FETCH_OBJ_R on a known property, the IS_UNDEF guard was conditionally skipped when a result type guard (MAY_BE_GUARD) was present and current_frame was set. The assumption was that deoptimization from the result type guard would handle IS_UNDEF by dispatching to opline->handler to re-execute in the interpreter.

However, when a side trace is compiled and linked into the parent trace's exit stub, it replaces opline->handler with the JIT code entry point. When unset() makes a property IS_UNDEF, the deoptimization path jumps to opline->handler which now points back to the same JIT code, creating an infinite loop. The loop never calls zend_jit_trace_exit(), so no exit counters are bumped and no blacklisting occurs.

The fix removes the conditional skip and always generates the IS_UNDEF guard on hot traces, ensuring the exit stub is taken when the property is undefined.

Test note: gh21267.phpt overrides opcache.jit_hot_* counters to defaults because run-tests.php forces them to 1, which changes trace compilation order and prevents the bug from triggering.

When JIT compiles a side trace for FETCH_OBJ_R on a known property,
the IS_UNDEF guard was conditionally skipped when a result type guard
(MAY_BE_GUARD) was present. The assumption was that deoptimization
from the result type guard would handle IS_UNDEF via the interpreter.

However, when a side trace replaces opline->handler with JIT code,
the deoptimization path dispatches back to opline->handler which now
points to the JIT entry, creating an infinite loop that never reaches
the interpreter or exit counter logic.

Always generate the IS_UNDEF guard on hot traces regardless of
MAY_BE_GUARD presence.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

JIT tracing: infinite loop on FETCH_OBJ_R with IS_UNDEF property in polymorphic context

1 participant