Skip to content

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

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from

Conversation

MaxKellermann
Copy link
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
Contributor Author

AppVeyor failure unrelated to this PR.

@arnaud-lb
Copy link
Member

This looks good to me

@dstogov do you confirm?

Copy link
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
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
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
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
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