Skip to content

Commit 93b6997

Browse files
committed
YJIT: Fix overlapping &mut in Assembler::code_gc()
Making overlapping `&mut`s triggers Undefined Bahavior. This function previously had them through `cb` and `ocb` aliasing with `self` or live references in the caller. To fix the overlap, take `ocb` as a parameter and don't use `get_inline_cb()` in the body of the function.
1 parent a8c6ba2 commit 93b6997

3 files changed

Lines changed: 11 additions & 14 deletions

File tree

yjit/src/asm/mod.rs

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -583,7 +583,7 @@ impl CodeBlock {
583583
}
584584

585585
/// Code GC. Free code pages that are not on stack and reuse them.
586-
pub fn code_gc(&mut self) {
586+
pub fn code_gc(&mut self, ocb: &mut OutlinedCb) {
587587
// The previous code GC failed to free any pages. Give up.
588588
if self.freed_pages.as_ref() == &Some(vec![]) {
589589
return;
@@ -631,15 +631,11 @@ impl CodeBlock {
631631
freed_pages.append(&mut virtual_pages);
632632

633633
if let Some(&first_page) = freed_pages.first() {
634-
let mut cb = CodegenGlobals::get_inline_cb();
635-
cb.write_pos = cb.get_page_pos(first_page);
636-
cb.dropped_bytes = false;
637-
cb.clear_comments();
638-
639-
let mut ocb = CodegenGlobals::get_outlined_cb().unwrap();
640-
ocb.write_pos = ocb.get_page_pos(first_page);
641-
ocb.dropped_bytes = false;
642-
ocb.clear_comments();
634+
for cb in [&mut *self, ocb.unwrap()] {
635+
cb.write_pos = cb.get_page_pos(first_page);
636+
cb.dropped_bytes = false;
637+
cb.clear_comments();
638+
}
643639
}
644640

645641
// Track which pages are free.

yjit/src/core.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2049,7 +2049,7 @@ pub fn gen_entry_point(iseq: IseqPtr, ec: EcPtr) -> Option<CodePtr> {
20492049
// Compilation failed
20502050
None => {
20512051
// Trigger code GC. This entry point will be recompiled later.
2052-
cb.code_gc();
2052+
cb.code_gc(ocb);
20532053
return None;
20542054
}
20552055

@@ -2146,7 +2146,7 @@ fn entry_stub_hit_body(entry_ptr: *const c_void, ec: EcPtr) -> Option<*const u8>
21462146
Some(blockref) => blockref,
21472147
None => { // No space
21482148
// Trigger code GC. This entry point will be recompiled later.
2149-
cb.code_gc();
2149+
cb.code_gc(ocb);
21502150
return None;
21512151
}
21522152
}
@@ -2426,7 +2426,7 @@ fn branch_stub_hit_body(branch_ptr: *const c_void, target_idx: u32, ec: EcPtr) -
24262426
// because incomplete code could be used when cb.dropped_bytes is flipped
24272427
// by code GC. So this place, after all compilation, is the safest place
24282428
// to hook code GC on branch_stub_hit.
2429-
cb.code_gc();
2429+
cb.code_gc(ocb);
24302430

24312431
// Failed to service the stub by generating a new block so now we
24322432
// need to exit to the interpreter at the stubbed location. We are

yjit/src/yjit.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,8 @@ pub extern "C" fn rb_yjit_code_gc(_ec: EcPtr, _ruby_self: VALUE) -> VALUE {
140140
}
141141

142142
let cb = CodegenGlobals::get_inline_cb();
143-
cb.code_gc();
143+
let ocb = CodegenGlobals::get_outlined_cb();
144+
cb.code_gc(ocb);
144145
Qnil
145146
}
146147

0 commit comments

Comments
 (0)