diff --git a/crates/stdlib/src/faulthandler.rs b/crates/stdlib/src/faulthandler.rs index b8d7fe9f91b..265bcf9ca6d 100644 --- a/crates/stdlib/src/faulthandler.rs +++ b/crates/stdlib/src/faulthandler.rs @@ -252,7 +252,7 @@ mod decl { /// Dump a single frame's info to fd (signal-safe), reading live data. #[cfg(any(unix, windows))] fn dump_frame_from_raw(fd: i32, frame: &Frame) { - let filename = frame.code.source_path.as_str(); + let filename = frame.code.source_path().as_str(); let funcname = frame.code.obj_name.as_str(); let lasti = frame.lasti(); let lineno = if lasti == 0 { @@ -328,7 +328,7 @@ mod decl { #[cfg(any(unix, windows))] fn dump_frame_from_ref(fd: i32, frame: &crate::vm::PyRef) { let funcname = frame.code.obj_name.as_str(); - let filename = frame.code.source_path.as_str(); + let filename = frame.code.source_path().as_str(); let lineno = if frame.lasti() == 0 { frame.code.first_line_number.map(|n| n.get()).unwrap_or(1) as u32 } else { diff --git a/crates/vm/src/builtins/code.rs b/crates/vm/src/builtins/code.rs index 932100db94f..bf6cf7071cc 100644 --- a/crates/vm/src/builtins/code.rs +++ b/crates/vm/src/builtins/code.rs @@ -15,6 +15,7 @@ use alloc::fmt; use core::{borrow::Borrow, ops::Deref}; use malachite_bigint::BigInt; use num_traits::Zero; +use rustpython_common::lock::PyMutex; use rustpython_compiler_core::{OneIndexed, bytecode::CodeUnits, bytecode::PyCodeLocationInfoKind}; /// State for iterating through code address ranges @@ -323,6 +324,7 @@ impl> IntoCodeObject for frozen::FrozenCodeObject { #[pyclass(module = false, name = "code")] pub struct PyCode { pub code: CodeObject, + source_path: PyMutex<&'static PyStrInterned>, } impl Deref for PyCode { @@ -333,8 +335,20 @@ impl Deref for PyCode { } impl PyCode { - pub const fn new(code: CodeObject) -> Self { - Self { code } + pub fn new(code: CodeObject) -> Self { + let sp = code.source_path; + Self { + code, + source_path: PyMutex::new(sp), + } + } + + pub fn source_path(&self) -> &'static PyStrInterned { + *self.source_path.lock() + } + + pub fn set_source_path(&self, new: &'static PyStrInterned) { + *self.source_path.lock() = new; } pub fn from_pyc_path(path: &std::path::Path, vm: &VirtualMachine) -> PyResult> { let name = match path.file_stem() { @@ -397,7 +411,7 @@ impl Representable for PyCode { "", code.obj_name, zelf.get_id(), - code.source_path.as_str(), + zelf.source_path().as_str(), code.first_line_number.map_or(-1, |n| n.get() as i32) )) } @@ -572,7 +586,7 @@ impl PyCode { #[pygetset] pub fn co_filename(&self) -> PyStrRef { - self.code.source_path.to_owned() + self.source_path().to_owned() } #[pygetset] @@ -906,7 +920,7 @@ impl PyCode { let source_path = match co_filename { OptionalArg::Present(source_path) => source_path, - OptionalArg::Missing => self.code.source_path.to_owned(), + OptionalArg::Missing => self.source_path().to_owned(), }; let first_line_number = match co_firstlineno { diff --git a/crates/vm/src/builtins/traceback.rs b/crates/vm/src/builtins/traceback.rs index ff88a03f7de..66d999b26b4 100644 --- a/crates/vm/src/builtins/traceback.rs +++ b/crates/vm/src/builtins/traceback.rs @@ -131,7 +131,7 @@ impl serde::Serialize for PyTraceback { let mut struc = s.serialize_struct("PyTraceback", 3)?; struc.serialize_field("name", self.frame.code.obj_name.as_str())?; struc.serialize_field("lineno", &self.lineno.get())?; - struc.serialize_field("filename", self.frame.code.source_path.as_str())?; + struc.serialize_field("filename", self.frame.code.source_path().as_str())?; struc.end() } } diff --git a/crates/vm/src/exceptions.rs b/crates/vm/src/exceptions.rs index 9c559945a59..3a1652a28de 100644 --- a/crates/vm/src/exceptions.rs +++ b/crates/vm/src/exceptions.rs @@ -383,7 +383,7 @@ fn write_traceback_entry( output: &mut W, tb_entry: &Py, ) -> Result<(), W::Error> { - let filename = tb_entry.frame.code.source_path.as_str(); + let filename = tb_entry.frame.code.source_path().as_str(); writeln!( output, r##" File "{}", line {}, in {}"##, diff --git a/crates/vm/src/frame.rs b/crates/vm/src/frame.rs index 91b0f59b46c..df726b5f684 100644 --- a/crates/vm/src/frame.rs +++ b/crates/vm/src/frame.rs @@ -3223,7 +3223,7 @@ impl ExecutingFrame<'_> { self.lasti(), self.code.obj_name, op_name, - self.code.source_path + self.code.source_path() ); } self.state.stack.drain(stack_len - count..).map(|obj| { diff --git a/crates/vm/src/import.rs b/crates/vm/src/import.rs index 31752dabb03..d61a018bb00 100644 --- a/crates/vm/src/import.rs +++ b/crates/vm/src/import.rs @@ -168,7 +168,7 @@ pub fn import_code_obj( if set_file_attr { attrs.set_item( identifier!(vm, __file__), - code_obj.source_path.to_object(), + code_obj.source_path().to_object(), vm, )?; } @@ -195,7 +195,7 @@ fn remove_importlib_frames_inner( return (None, false); }; - let file_name = traceback.frame.code.source_path.as_str(); + let file_name = traceback.frame.code.source_path().as_str(); let (inner_tb, mut now_in_importlib) = remove_importlib_frames_inner(vm, traceback.next.lock().clone(), always_trim); diff --git a/crates/vm/src/stdlib/imp.rs b/crates/vm/src/stdlib/imp.rs index c140d7cdcaf..cf9aba02265 100644 --- a/crates/vm/src/stdlib/imp.rs +++ b/crates/vm/src/stdlib/imp.rs @@ -229,7 +229,7 @@ mod _imp { #[pyfunction] fn _fix_co_filename(code: PyRef, path: PyStrRef, vm: &VirtualMachine) { - let old_name = code.code.source_path; + let old_name = code.source_path(); let new_name = vm.ctx.intern_str(path.as_str()); super::update_code_filenames(&code, old_name, new_name); } @@ -288,18 +288,11 @@ fn update_code_filenames( old_name: &'static PyStrInterned, new_name: &'static PyStrInterned, ) { - if !core::ptr::eq(code.code.source_path, old_name) - && code.code.source_path.as_str() != old_name.as_str() - { + let current = code.source_path(); + if !core::ptr::eq(current, old_name) && current.as_str() != old_name.as_str() { return; } - // SAFETY: called during import before the code object is shared. - // Mutates co_filename in place. - #[allow(invalid_reference_casting)] - unsafe { - let source_path_ptr = &code.code.source_path as *const _ as *mut &'static PyStrInterned; - core::ptr::write_volatile(source_path_ptr, new_name); - } + code.set_source_path(new_name); for constant in code.code.constants.iter() { let obj: &crate::PyObject = constant.borrow(); if let Some(inner_code) = obj.downcast_ref::() { diff --git a/crates/vm/src/stdlib/io.rs b/crates/vm/src/stdlib/io.rs index c6af68f476a..b15c0e80404 100644 --- a/crates/vm/src/stdlib/io.rs +++ b/crates/vm/src/stdlib/io.rs @@ -4971,7 +4971,7 @@ mod _io { && let Some(frame) = vm.current_frame() && let Some(stdlib_dir) = vm.state.config.paths.stdlib_dir.as_deref() { - let path = frame.code.source_path.as_str(); + let path = frame.code.source_path().as_str(); if !path.starts_with(stdlib_dir) { stacklevel = stacklevel.saturating_sub(1); } diff --git a/crates/vm/src/vm/context.rs b/crates/vm/src/vm/context.rs index faf14a78664..db5406f045f 100644 --- a/crates/vm/src/vm/context.rs +++ b/crates/vm/src/vm/context.rs @@ -658,7 +658,7 @@ impl Context { pub fn new_code(&self, code: impl code::IntoCodeObject) -> PyRef { let code = code.into_code_object(self); - PyRef::new_ref(PyCode { code }, self.types.code_type.to_owned(), None) + PyRef::new_ref(PyCode::new(code), self.types.code_type.to_owned(), None) } } diff --git a/crates/vm/src/warn.rs b/crates/vm/src/warn.rs index 47e6f5af9c5..b4406ff5246 100644 --- a/crates/vm/src/warn.rs +++ b/crates/vm/src/warn.rs @@ -578,7 +578,7 @@ fn setup_context( } let (globals, filename, lineno) = if let Some(f) = f { - (f.globals.clone(), f.code.source_path, f.f_lineno()) + (f.globals.clone(), f.code.source_path(), f.f_lineno()) } else if let Some(frame) = vm.current_frame() { // We have a frame but it wasn't found during stack walking (frame.globals.clone(), vm.ctx.intern_str(""), 1)