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)