Skip to content

Tracing JIT: give the type guard on entry of an inlined call an exit opline - #24411

Closed
waroad wants to merge 1 commit into
php:PHP-8.4from
waroad:traj-s-20261017-011712-04-trace-exit-opline-assert-pr2
Closed

waroad wants to merge 1 commit into
php:PHP-8.4from
waroad:traj-s-20261017-011712-04-trace-exit-opline-assert-pr2

Conversation

@waroad

@waroad waroad commented Oct 18, 2026

Copy link
Copy Markdown
Contributor

Here is the patch I offered in the issue, thanks for the go-ahead.

When the tracing JIT inlines a call (ZEND_JIT_TRACE_ENTER) and some of the callee's CVs are register-allocated with ZREG_LOAD and still MAY_BE_GUARD, it emits a type guard for them with a NULL opline. A NULL exit opline means "EX(opline) is already valid", but at this point the frame is the freshly pushed callee whose EX(opline) has not been written yet. So when the guard fails (here: the reference-bound arguments are ints while the trace is recorded and floats on a later call), zend_jit_trace_exit() resumes the VM at a garbage opline. A debug build trips the opline assertion; a release build segfaults (as reported in the issue).

The fix passes (p+1)->opline, the callee's first traced opline, the same opline the SEND_UNPACK/SEND_ARRAY guard just above uses. A failing guard then exits to the start of the callee instead.

The test ext/opcache/tests/jit/gh24389.phpt is the reproducer from the issue, plus a check of the return values. On a PHP-8.4 debug ASan build it fails the zend_jit_trace_exit assertion without the fix and passes with it. The issue's reproducer and its foreach by-reference variant now run to completion, and the variant prints the same as with the JIT off. With the fix, ext/opcache/tests has the same three failures under the tracing and the function JIT (gh9259_003, preload_parse_error, log_verbosity_bug). They are LeakSanitizer reports from this ASan build, and they fail the same way without the fix under the tracing JIT.

Fixes #24389.

Found with an LLM-based testing tool; I wrote this fix with help from Claude and reviewed it myself.

@ndossche ndossche left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this to be right.
This was introduced by another bugfix c5ce74c, so that bugfix assumed the opline would always be set in EX(), but apparently not.

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: segfault when an inlined call's reference argument changes from int to float (zend_jit_trace_exit assertion)

2 participants