openj9 icon indicating copy to clipboard operation
openj9 copied to clipboard

Improve JIT memory protection on AArch64 macOS

Open knn-k opened this issue 3 years ago • 3 comments
trafficstars

You need to call pthread_jit_write_protect_np() before and after writing to JIT code cache on AArch64 macOS. JIT compiler currently calls the API in various places, and it is not easy to understand.

knn-k avatar Mar 04 '22 23:03 knn-k

From the comment https://github.com/eclipse-openj9/openj9/pull/15907#discussion_r973092054:

I suggest we're overdue for the introduction of a helper function for this (that would do nothing on platforms where it's not required). The need for it may extend to other platforms in the future: a helper function would make dealing with that much more straight-forward.

knn-k avatar Sep 19 '22 22:09 knn-k

AArch64 macOS seems to have no API for getting the current protection mode of a thread. We can do like the following if there is such an API. We need a different solution. Perhaps adding a new entry for the protection mode in thread-local storage?

Entering the section for writing to code cache:

prev_mode = get_current_protection_mode(); // No such API available
if (prev_mode == not_writable) {
    pthread_jit_write_protect_np(0); // Enable writing to code cache
}

Exiting the section for writing to code cache:

if (prev_mode == not_writable) {
    pthread_jit_write_protect_np(1); // Stop writing to code cache
}

knn-k avatar Sep 20 '22 01:09 knn-k

I think the TLH solution will solve a lot of concerns, including ones I had brought up a few months ago in the relo code. The TLH can be a counter that gets incremented when one wishes to write to the code cache, and decremented when one wishes to not allow writes to the code cache. This will ensure that recursive calls do not result in a crash, eg:

set writable();   // CC RW
set writable();   // CC RW
  ...
set_unwritable(); // CC RW

// writing to code cache here will not crash

set_unwritable(); // CC RX

FWIW, we can also introduce an API to force RX regardless of scope. However, at least in the scope of a compilation, I don't see this being necessary. The reason for this is we should use RAII as suggested by @Akira1Saitoh in https://github.com/eclipse-openj9/openj9/issues/15518#issuecomment-1247392757.

The RAII object will save the value of the TLH counter at construction and invoke set_writable(); in the destructor, it should invoke set_unwritable() as many times as needed to restore the value of the TLH counter to what it was in the constructor. This then addresses any issues related to exceptions. Ideally we would use RAII as much as possible.

In order to deal with the problem of not knowing the state of the protection mode, at thread start, we force it to one state or another, so that we always know what the outer-most scope's state is.

dsouzai avatar Sep 20 '22 02:09 dsouzai