Skip to content

Tracing JIT: keep the SEND_VAL type guard after assigning to a reference - #24651

Open
waroad wants to merge 1 commit into
php:PHP-8.4from
waroad:traj-s-20261017-005254-06-typed-ref-assign-result-bits-pr2
Open

waroad wants to merge 1 commit into
php:PHP-8.4from
waroad:traj-s-20261017-005254-06-typed-ref-assign-result-bits-pr2

Conversation

@waroad

@waroad waroad commented Oct 24, 2026

Copy link
Copy Markdown
Contributor

@ndossche here is the patch I offered in the issue, as you asked.

With opcache.jit=tracing, a trace like sink($x = $y + 2) can be recorded while $x is a reference to an untyped property, then run while $x is a reference to a typed float (or string) property. When that happens, sink() receives an int holding the raw bits of the converted value: int(4617315517961601024) instead of float(5), and for a string property an unrelated int (int(1097804056) in my run) instead of string(1) "5".

When an ASSIGN result goes straight into the following SEND_VAL, the tracing JIT fuses the two. The result is written directly into the callee's argument slot, the SEND_VAL is skipped, and the callee's parameter takes the type recorded for the SEND_VAL operand. That type was never checked. It's fine when the result is a copy of the guarded op2, but the typed reference helper can coerce the value, so the recorded type may be wrong. The fix stops fusing in that case: when op1 is a guarded reference (ref_addr is set), the result goes to its own slot as usual, and SEND_VAL checks its type and side-exits if it doesn't match. The reference branch also had a second copy of the result address / send-fusion code, which the shared code right after it already does. I removed that copy so there is only one place to apply the condition.

The new test ext/opcache/tests/jit/gh24436.phpt runs the same call site with untyped, typed float and typed string property references. It fails without the patch and passes with it, both with run-tests' defaults and with CI's tracing JIT options. The reproducer from the issue, run with the command line given there, also prints int(4617315517961601024) before the patch and float(5) after. ext/opcache/tests passes in both tracing and function JIT modes. I based this on PHP-8.4 since that's the branch I reproduced and tested on.

Fixes #24436.

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 was confused first by the removal, but it's really just a duplicated code block. The condition added is for the trace reference path, so I think this is right.

@ndossche

Copy link
Copy Markdown
Member

cc @iliaal Can you double check please

@iliaal iliaal 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.

Was a bit thrown off by the removal as well, but it is a correct change.

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.

Tracing JIT: value of $x = $y + 2 is int with raw double bits when $x is a reference to a typed float property

3 participants