ext/opcache/jit: handle zend_jit_find_trace() failures

Commit 6c25413 added the flag ZEND_JIT_EXIT_INVALIDATE which resets
the trace handlers in zend_jit_trace_exit(), but forgot to consider
that on ZEND_JIT_TRACE_STOP_LINK, this changed handler gets passed to
zend_jit_find_trace(), causing it to fail, either by returning 0
(results in bogus data) or by aborting due to ZEND_UNREACHABLE().  In
either case, this crashes the PHP process.

I'm not quite sure how to fix this multi-threading problem properly;
my suggestion is to just fail the zend_jit_trace() call.  After all,
the whole ZEND_JIT_EXIT_INVALIDATE fix was about reloading modified
scripts, so there's probably no point in this pending zend_jit_trace()
call.
This commit is contained in:
Max Kellermann 2022-12-22 13:02:52 +01:00 committed by David Carlier
parent a3891d9d1a
commit b26b758952
2 changed files with 17 additions and 1 deletions

1
NEWS
View File

@ -24,6 +24,7 @@ PHP NEWS
- Opcache:
. Fix inverted bailout value in zend_runtime_jit() (Max Kellermann).
. Fix access to uninitialized variable in accel_preload(). (nielsdos)
. Fix zend_jit_find_trace() crashes. (Max Kellermann)
- PHPDBG:
. Fix undefined behaviour in phpdbg_load_module_or_extension(). (nielsdos)

View File

@ -247,6 +247,13 @@ static void zend_jit_trace_add_code(const void *start, uint32_t size)
t->code_size = size;
}
/**
* Locate a trace in the #zend_jit_traces array with the specified
* #code_start address.
*
* @return the #zend_jit_traces index or 0 if no such #code_start
* address was found
*/
static uint32_t zend_jit_find_trace(const void *addr)
{
uint32_t i;
@ -256,7 +263,6 @@ static uint32_t zend_jit_find_trace(const void *addr)
return i;
}
}
ZEND_UNREACHABLE();
return 0;
}
@ -6843,6 +6849,15 @@ done:
const void *timeout_exit_addr = NULL;
t->link = zend_jit_find_trace(p->opline->handler);
if (t->link == 0) {
/* this can happen if ZEND_JIT_EXIT_INVALIDATE was handled
* by zend_jit_trace_exit() in another thread after this
* thread set ZEND_JIT_TRACE_STOP_LINK in zend_jit_trace_execute();
* ZEND_JIT_EXIT_INVALIDATE resets the opline handler to one of
* the "_counter_handler" functions, and these are not registered
* tracer functions */
goto jit_failure;
}
if ((zend_jit_traces[t->link].flags & ZEND_JIT_TRACE_USES_INITIAL_IP)
&& !zend_jit_set_ip(&dasm_state, p->opline)) {
goto jit_failure;