diff options
author | Alan Wu <XrXr@users.noreply.github.com> | 2023-03-15 13:43:49 -0400 |
---|---|---|
committer | Alan Wu <XrXr@users.noreply.github.com> | 2023-03-15 15:45:20 -0400 |
commit | de174681f7db3cc84ee8c55cafe89bb85a77e945 (patch) | |
tree | 98d3394c448380ee3180e97679de97de11ad9a3a | |
parent | f613c18912f4bf5492a8dc02ab5e3661f4ae907c (diff) | |
download | ruby-de174681f7db3cc84ee8c55cafe89bb85a77e945.tar.gz |
YJIT: Assert that we have the VM lock while marking
Somewhat important because having the lock is a key part of the
soundness reasoning for the `unsafe` usage here.
-rw-r--r-- | yjit.c | 8 | ||||
-rw-r--r-- | yjit/bindgen/src/main.rs | 2 | ||||
-rw-r--r-- | yjit/src/core.rs | 24 | ||||
-rw-r--r-- | yjit/src/cruby_bindings.inc.rs | 1 |
4 files changed, 29 insertions, 6 deletions
@@ -1100,6 +1100,14 @@ object_shape_count(rb_execution_context_t *ec, VALUE self) return ULONG2NUM((unsigned long)GET_VM()->next_shape_id); } +// Assert that we have the VM lock. Relevant mostly for multi ractor situations. +// The GC takes the lock before calling us, and this asserts that it indeed happens. +void +rb_yjit_assert_holding_vm_lock(void) +{ + ASSERT_vm_locking(); +} + // Primitives used by yjit.rb VALUE rb_yjit_stats_enabled_p(rb_execution_context_t *ec, VALUE self); VALUE rb_yjit_trace_exit_locations_enabled_p(rb_execution_context_t *ec, VALUE self); diff --git a/yjit/bindgen/src/main.rs b/yjit/bindgen/src/main.rs index bf762c1401..3dc503f7c3 100644 --- a/yjit/bindgen/src/main.rs +++ b/yjit/bindgen/src/main.rs @@ -320,6 +320,8 @@ fn main() { .allowlist_function("rb_yjit_exit_locations_dict") .allowlist_function("rb_yjit_icache_invalidate") .allowlist_function("rb_optimized_call") + .allowlist_function("rb_yjit_assert_holding_vm_lock") + // from vm_sync.h .allowlist_function("rb_vm_barrier") diff --git a/yjit/src/core.rs b/yjit/src/core.rs index 4467145f73..5686808b3a 100644 --- a/yjit/src/core.rs +++ b/yjit/src/core.rs @@ -863,9 +863,15 @@ pub extern "C" fn rb_yjit_iseq_mark(payload: *mut c_void) { // Nothing to mark. return; } else { - // SAFETY: It looks like the GC takes the VM lock while marking - // so we should be satisfying aliasing rules here. - unsafe { &*(payload as *const IseqPayload) } + // SAFETY: The GC takes the VM lock while marking, which + // we assert, so we should be synchronized and data race free. + // + // For aliasing, having the VM lock hopefully also implies that no one + // else has an overlapping &mut IseqPayload. + unsafe { + rb_yjit_assert_holding_vm_lock(); + &*(payload as *const IseqPayload) + } }; // For marking VALUEs written into the inline code block. @@ -915,9 +921,15 @@ pub extern "C" fn rb_yjit_iseq_update_references(payload: *mut c_void) { // Nothing to update. return; } else { - // SAFETY: It looks like the GC takes the VM lock while updating references - // so we should be satisfying aliasing rules here. - unsafe { &*(payload as *const IseqPayload) } + // SAFETY: The GC takes the VM lock while marking, which + // we assert, so we should be synchronized and data race free. + // + // For aliasing, having the VM lock hopefully also implies that no one + // else has an overlapping &mut IseqPayload. + unsafe { + rb_yjit_assert_holding_vm_lock(); + &*(payload as *const IseqPayload) + } }; // Evict other threads from generated code since we are about to patch them. diff --git a/yjit/src/cruby_bindings.inc.rs b/yjit/src/cruby_bindings.inc.rs index 190b163b41..19cea5e682 100644 --- a/yjit/src/cruby_bindings.inc.rs +++ b/yjit/src/cruby_bindings.inc.rs @@ -1333,4 +1333,5 @@ extern "C" { file: *const ::std::os::raw::c_char, line: ::std::os::raw::c_int, ); + pub fn rb_yjit_assert_holding_vm_lock(); } |