Skip to content

ext/opcache/jit/zend_jit_trace: add missing lock for EXIT_INVALIDATE#10138

Closed
MaxKellermann wants to merge 1 commit intophp:PHP-8.1from
CM4all:exit_invalidate_lock
Closed

ext/opcache/jit/zend_jit_trace: add missing lock for EXIT_INVALIDATE#10138
MaxKellermann wants to merge 1 commit intophp:PHP-8.1from
CM4all:exit_invalidate_lock

Conversation

@MaxKellermann
Copy link
Copy Markdown
Contributor

Commit 6c25413 added the flag ZEND_JIT_EXIT_INVALIDATE which resets the trace handlers in zend_jit_trace_exit(), but forgot to lock the shared memory section.

This could cause another worker process who still saw the ZEND_JIT_TRACE_JITED flag to schedule ZEND_JIT_TRACE_STOP_LINK, but when it arrived at the ZEND_JIT_DEBUG_TRACE_STOP, the handler was already reverted by the first worker process and thus zend_jit_find_trace() fails.

This in turn generated a bogus jump offset in the JITed code, crashing the PHP process.

@MaxKellermann MaxKellermann changed the base branch from master to PHP-8.1 December 20, 2022 15:16
@MaxKellermann
Copy link
Copy Markdown
Contributor Author

AppVeyor failure unrelated to this PR.

@arnaud-lb
Copy link
Copy Markdown
Member

This looks good to me

@dstogov do you confirm?

Copy link
Copy Markdown
Member

@dstogov dstogov left a comment

Choose a reason for hiding this comment

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

The additional lock is right of course but probably not enough. After the lock we should check some race conditions. E.g.

	/* Checks under lock */
	if (!(ZEND_OP_TRACE_INFO(opline, offset)->trace_flags & (ZEND_JIT_TRACE_JITED|ZEND_JIT_TRACE_BLACKLISTED))) {
		/* skip */;
	} else if (ZEND_JIT_TRACE_NUM >= JIT_G(max_root_traces)) {
		/* skip */;

Also it seems like, invalidating doesn't reset JITED/BLACKLISTED flags that should prevent re-compilation. Could you please take care about this.

@dstogov
Copy link
Copy Markdown
Member

dstogov commented Dec 26, 2022

Also it seems like, invalidating doesn't reset JITED/BLACKLISTED flags that should prevent re-compilation. Could you please take care about this.

Oh, I missed. These flag are already properly reset. So we need just additional checks to prevent "double" invalidations.

Commit 6c25413 added the flag ZEND_JIT_EXIT_INVALIDATE which
resets the trace handlers in zend_jit_trace_exit(), but forgot to
lock the shared memory section.

This could cause another worker process who still saw the
ZEND_JIT_TRACE_JITED flag to schedule ZEND_JIT_TRACE_STOP_LINK, but
when it arrived at the ZEND_JIT_DEBUG_TRACE_STOP, the handler was
already reverted by the first worker process and thus
zend_jit_find_trace() fails.

This in turn generated a bogus jump offset in the JITed code, crashing
the PHP process.
@MaxKellermann
Copy link
Copy Markdown
Contributor Author

After the lock we should check some race conditions

Thanks @dstogov, I added the checks you posted, but I'm not sure what else may be missing - I only recently read the JIT code for the first time, and those internals are still obscure to me. Please check if this is ok for merging.

Copy link
Copy Markdown
Member

@dstogov dstogov left a comment

Choose a reason for hiding this comment

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

This looks fine.

@devnexen
Copy link
Copy Markdown
Member

Merged via e217138b. Thank you

@devnexen devnexen closed this Dec 29, 2022
@MaxKellermann MaxKellermann deleted the exit_invalidate_lock branch December 31, 2022 06:01
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.

4 participants