Skip to content

JIT: Fix run_time_cache offset stored without map_ptr dereference#123

Closed
iliaal wants to merge 3 commits into
PHP-8.5from
fix/gh-22443-jit-runtime-cache
Closed

JIT: Fix run_time_cache offset stored without map_ptr dereference#123
iliaal wants to merge 3 commits into
PHP-8.5from
fix/gh-22443-jit-runtime-cache

Conversation

@iliaal

@iliaal iliaal commented Jun 25, 2026

Copy link
Copy Markdown
Owner

The tracing JIT could store a raw zend_map_ptr offset into EX(run_time_cache) for a polymorphic dynamic call ($callable(...)) that resolves to a non-closure function or method, so the interpreter dereferenced a bogus address on the next cached lookup. The codegen took the closure direct-pointer shortcut based on TRACE_FRAME_IS_CLOSURE_CALL, but that flag is set for every ZEND_INIT_DYNAMIC_CALL regardless of the resolved callee.

Restricting the shortcut to statically-known closures is safe: an invoked closure object always carries a resolved direct run_time_cache pointer (zend_closures.c), even when its persistent template is offset-tagged under opcache SHM or file_cache. Regression from 6872432.

iliaal added 3 commits June 25, 2026 18:14
fputcsv() and next() reached the file stream without the
CHECK_SPL_FILE_OBJECT_IS_INITIALIZED guard their siblings carry, so
invoking them via reflection on an object from
newInstanceWithoutConstructor() (constructor bypassed, stream NULL)
crashed instead of throwing. next() only touches the stream with the
READ_AHEAD flag, itself settable through the equally unguarded
setFlags(). Both now throw "Object not initialized".

Fixes phpGH-16217
Closes phpGH-22454
* PHP-8.4:
  Guard uninitialized SplFileObject in fputcsv() and next()
zend_jit_do_fcall() loaded the callee run_time_cache through the closure
direct-pointer shortcut whenever the call frame was flagged as a closure
call. That flag is set for every ZEND_INIT_DYNAMIC_CALL, but a dynamic
call may resolve to a non-closure function whose run_time_cache is a
zend_map_ptr offset. The raw offset was then stored into
EX(run_time_cache) without resolving it through CG(map_ptr_base), and a
later cache lookup dereferenced a bogus address.

Restrict the shortcut to statically-known closures. Unknown dynamic
calls fall through to the general path, which resolves both offsets and
direct pointers.

Fixes phpGH-22443
@iliaal iliaal force-pushed the fix/gh-22443-jit-runtime-cache branch from f6ff178 to f4d3234 Compare June 25, 2026 22:32
@iliaal

iliaal commented Jun 25, 2026

Copy link
Copy Markdown
Owner Author

Promoted to upstream: php#22459.

@iliaal iliaal closed this Jun 25, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant