Skip to content

Conversation

@khasinski
Copy link

@khasinski khasinski commented Jan 16, 2026

Fixes #20818

Problem

When FE_RESET_RW (foreach by-reference) executes, it converts the CV to a zend_reference before checking if the array/object is empty. However, when the JIT creates exit points for FE_RESET_RW in zend_jit_trace_handler(), it was not updating the stack type for op1 to reflect this change.

This caused side traces compiled from these exit points to have incorrect type information. The side trace CV cleanup code would see IS_OBJECT and generate a direct call to zend_objects_store_del(), but the actual value was a zend_reference*, causing a segfault.

Solution

Add ZEND_FE_RESET_RW to the list of opcodes that temporarily set their op1 stack type to IS_UNKNOWN before creating exit points. This follows the same pattern already used for ZEND_BIND_INIT_STATIC_OR_JMP and ZEND_FE_FETCH_R/RW.

When IS_UNKNOWN, the JIT falls back to SSA type info which correctly includes MAY_BE_REF for FE_RESET_RW op1_def (see zend_inference.c:3483-3484).

Changes

  • ext/opcache/jit/zend_jit_ir.c: Add ZEND_FE_RESET_RW case to both switch blocks in zend_jit_trace_handler() that handle stack type updates around exit point creation
  • ext/opcache/tests/jit/gh20818.phpt: Test case from the issue

Testing

  • Test passes with opcache.protect_memory=1
  • All 468 JIT tests pass with no regressions

@khasinski khasinski requested a review from dstogov as a code owner January 16, 2026 02:40
@khasinski khasinski marked this pull request as draft January 16, 2026 02:42
When FE_RESET_RW executes, it converts the CV to a reference before
checking if the array/object is empty. However, when the JIT creates
exit points for FE_RESET_RW in zend_jit_trace_handler(), it wasn't
updating the stack type for op1 to reflect this change.

This caused side traces compiled from these exit points to have
incorrect type information. The side trace's CV cleanup code would
see IS_OBJECT and generate a direct call to zend_objects_store_del(),
but the actual value was a zend_reference*, causing a segfault.

The fix adds ZEND_FE_RESET_RW to the list of opcodes that temporarily
set their op1 stack type to IS_UNKNOWN before creating exit points.
This follows the same pattern used for ZEND_BIND_INIT_STATIC_OR_JMP.
When IS_UNKNOWN, the JIT falls back to SSA type info which correctly
includes MAY_BE_REF for FE_RESET_RW's op1_def.
@khasinski khasinski force-pushed the fix/gh-20818-jit-object-reference branch from e991cfe to cd2ca57 Compare January 16, 2026 23:25
@khasinski khasinski marked this pull request as ready for review January 17, 2026 00:11
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.

Segfault in Tracing JIT with Object Reference

1 participant