mirror of
https://github.com/RustPython/RustPython.git
synced 2026-10-28 18:59:04 +08:00
Replace unsafe pointer cast with PyMutex in PyCode (#7055)
Add `source_path: PyMutex<&'static PyStrInterned>` field to `PyCode` for interior mutability, replacing the UB-inducing `#[allow(invalid_reference_casting)]` + `write_volatile` pattern in `update_code_filenames`. Update all read sites across the codebase to use the new `source_path()` accessor method.
This commit is contained in:
1 parent
d1c19bef38
commit
dc2d235e59
10 files changed
+33
-26
No files matched your search
@@ -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<Frame>) {
|
||||
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 {
|
||||
|
||||
@@ -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<B: AsRef<[u8]>> IntoCodeObject for frozen::FrozenCodeObject<B> {
|
||||
#[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<PyRef<Self>> {
|
||||
let name = match path.file_stem() {
|
||||
@@ -397,7 +411,7 @@ impl Representable for PyCode {
|
||||
"<code object {} at {:#x} file {:?}, line {}>",
|
||||
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 {
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
@@ -383,7 +383,7 @@ fn write_traceback_entry<W: Write>(
|
||||
output: &mut W,
|
||||
tb_entry: &Py<PyTraceback>,
|
||||
) -> 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 {}"##,
|
||||
|
||||
@@ -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| {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -229,7 +229,7 @@ mod _imp {
|
||||
|
||||
#[pyfunction]
|
||||
fn _fix_co_filename(code: PyRef<PyCode>, 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::<PyCode>() {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -658,7 +658,7 @@ impl Context {
|
||||
|
||||
pub fn new_code(&self, code: impl code::IntoCodeObject) -> PyRef<PyCode> {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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("<sys>"), 1)
|
||||
|
||||
Reference in new issue
Block a user