Skip to content

Commit 4dad3e0

Browse files
committed
Replace unsafe pointer cast with AtomicPtr in PyCode
Add `source_path: AtomicPtr<PyStrInterned>` field to `PyCode` for interior mutability, replacing the UB-inducing `#[allow(invalid_reference_casting)]` + `write_volatile` pattern in `update_code_filenames`. Use atomic load/store instead of a mutex since the operation is a simple pointer swap on a 'static reference. Update all read sites to use `source_path()` accessor.
1 parent 65d54e8 commit 4dad3e0

File tree

1 file changed

+14
-7
lines changed

1 file changed

+14
-7
lines changed

crates/vm/src/builtins/code.rs

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,13 @@ use crate::{
1212
types::{Constructor, Representable},
1313
};
1414
use alloc::fmt;
15-
use core::{borrow::Borrow, ops::Deref};
15+
use core::{
16+
borrow::Borrow,
17+
ops::Deref,
18+
sync::atomic::{AtomicPtr, Ordering},
19+
};
1620
use malachite_bigint::BigInt;
1721
use num_traits::Zero;
18-
use rustpython_common::lock::PyMutex;
1922
use rustpython_compiler_core::{OneIndexed, bytecode::CodeUnits, bytecode::PyCodeLocationInfoKind};
2023

2124
/// State for iterating through code address ranges
@@ -324,7 +327,7 @@ impl<B: AsRef<[u8]>> IntoCodeObject for frozen::FrozenCodeObject<B> {
324327
#[pyclass(module = false, name = "code")]
325328
pub struct PyCode {
326329
pub code: CodeObject,
327-
source_path: PyMutex<&'static PyStrInterned>,
330+
source_path: AtomicPtr<PyStrInterned>,
328331
}
329332

330333
impl Deref for PyCode {
@@ -336,19 +339,23 @@ impl Deref for PyCode {
336339

337340
impl PyCode {
338341
pub fn new(code: CodeObject) -> Self {
339-
let sp = code.source_path;
342+
let sp = code.source_path as *const PyStrInterned as *mut PyStrInterned;
340343
Self {
341344
code,
342-
source_path: PyMutex::new(sp),
345+
source_path: AtomicPtr::new(sp),
343346
}
344347
}
345348

346349
pub fn source_path(&self) -> &'static PyStrInterned {
347-
*self.source_path.lock()
350+
// SAFETY: always points to a valid &'static PyStrInterned (interned strings are never deallocated)
351+
unsafe { &*self.source_path.load(Ordering::Relaxed) }
348352
}
349353

350354
pub fn set_source_path(&self, new: &'static PyStrInterned) {
351-
*self.source_path.lock() = new;
355+
self.source_path.store(
356+
new as *const PyStrInterned as *mut PyStrInterned,
357+
Ordering::Relaxed,
358+
);
352359
}
353360
pub fn from_pyc_path(path: &std::path::Path, vm: &VirtualMachine) -> PyResult<PyRef<Self>> {
354361
let name = match path.file_stem() {

0 commit comments

Comments
 (0)