Skip to content

Conversation

@arnaud-lb
Copy link
Member

This follows dstogov/ir@fe83fdf.

Opcache uses mprotect() to flip the writeable flag when opcache.protect_memory is on. JIT uses mprotect() to exchange the writeable and executable flags.

Here I use pkeys to replace the mprotect() calls.

Unfortunately I didn't see notable improvements in benchmarks.

IIRC opcache.protect_memory has a considerable impact on CI (maybe fuzzer too), so this may profit that.

See

cc @dstogov

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.

Thanks for checking this.
I wouldn't merge this without an improvement.
Probably, mprotect() overhead is invisible part of PHP/JIT compiler cost.

Comment on lines +3537 to +3541
# ifdef HAVE_PTHREAD_JIT_WRITE_PROTECT_NP
if (zend_write_protect) {
pthread_jit_write_protect_np(1);
}
# endif
Copy link
Member

Choose a reason for hiding this comment

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

I'm not sure how pthread_jit_write_protect_np() works together with mprotect() and PKEYS.

Comment on lines +41 to +42
# ifndef PKEY_DISABLE_EXECUTE
# define PKEY_DISABLE_EXECUTE 0
Copy link
Member

Choose a reason for hiding this comment

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

It seems we can't disable EXECUTE permission on x86_64. I didn't found a solution.

Comment on lines +3596 to +3601
# ifdef ZTS
int restrictions = 0;
# else
int restrictions = PKEY_DISABLE_EXECUTE;
# endif
if (pkey_set(pkey, restrictions) != 0) {
Copy link
Member

Choose a reason for hiding this comment

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

Why do we need #ifdef ZTS? I assume this us for AArch64. Linux or MacOS?
May be we should prefer pthread_jit_write_protect_np()?

Copy link
Member Author

@arnaud-lb arnaud-lb Nov 13, 2025

Choose a reason for hiding this comment

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

In the existing code, we avoid removing the PROT_EXEC in zend_jit_unprotect(), in ZTS, because other threads may be executing. I wanted to reproduce the same logic here: with restrictions = 0, we only remove PKEY_DISABLE_WRITE, thus allowing write without disallowing execute.

My understanding is that pthread_jit_write_protect_np() is MacOS only, while pkeys are Linux only.

Copy link
Member

Choose a reason for hiding this comment

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

In the existing code, we avoid removing the PROT_EXEC in zend_jit_unprotect(), in ZTS, because other threads may be executing. I wanted to reproduce the same logic here: with restrictions = 0, we only remove PKEY_DISABLE_WRITE, thus allowing write without disallowing execute.

  1. I understood that PKEYs are thread specific (may be I'm wrong).
  2. PKEY_DISABLE_EXECUTE is zero on x86_64. So this should affect only Arrach64/Linux. I didn't test this on real hardware.

My understanding is that pthread_jit_write_protect_np() is MacOS only, while pkeys are Linux only.

I understood the same.

@arnaud-lb
Copy link
Member Author

I wouldn't merge this without an improvement.

I agree. I will give it another look, and eventually close the PR.

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.

2 participants