GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — Fix thread-safety in GC, type cache, and instruction cache by youknowone · Pull Request #7355 · RustPython/RustPython

Fix thread-safety in GC, type cache, and instruction cache #7355

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

Sign up for GitHub

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
youknowone merged 6 commits into RustPython:main from youknowone:gc-use-after-free
Mar 5, 2026

Uh oh!

There was an error while loading. Please reload this page.

Merged

Fix thread-safety in GC, type cache, and instruction cache #7355

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
6 commits
Select commit Hold shift + click to select a range
70169e8
Fix thread-safety in GC, type cache, and instruction cache
youknowone Mar 5, 2026
b0ad917
Fix RLock _acquire_restore tuple handling and unxfail threading test
youknowone Mar 5, 2026
de01099
Align type cache seqlock writer protocol with CPython
youknowone Mar 5, 2026
8683977
RLock: use single parking_lot level, track recursion manually
youknowone Mar 5, 2026
3e31d22
Add try_to_owned_from_ptr to avoid &PyObject on stale ptrs
youknowone Mar 5, 2026
b3de227
Fix CI: spelling typo and xfail flaky test_thread_safety
youknowone Mar 5, 2026
File filter
Filter by extension

Clear filters
Conversations
Failed to load comments.
Loading

Uh oh!

There was an error while loading. Please reload this page.

Jump to
Jump to file
Failed to load files.
Loading

Uh oh!

There was an error while loading. Please reload this page.

Diff view
Diff view

There are no files selected for viewing

4 changes: 2 additions & 2 deletions 4 Lib/test/_test_multiprocessing.py
Show comments
View file
Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -4815,9 +4815,9 @@ def test_finalize(self):
result = [obj for obj in iter(conn.recv, 'STOP')]
self.assertEqual(result, ['a', 'b', 'd10', 'd03', 'd02', 'd01', 'e'])

# TODO: RUSTPYTHON - gc.get_threshold() and gc.set_threshold() not implemented
@unittest.expectedFailure
@support.requires_resource('cpu')
# TODO: RUSTPYTHON; dict iteration races with concurrent GC mutations
@unittest.expectedFailure
def test_thread_safety(self):
# bpo-24484: _run_finalizers() should be thread-safe
def cb():
Expand Down
4 changes: 0 additions & 4 deletions 4 Lib/test/test_threading.py
Show comments
View file
Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -2141,10 +2141,6 @@ def __init__(self, a, *, b) -> None:
CustomRLock(1, b=2)
self.assertEqual(warnings_log, [])

@unittest.expectedFailure # TODO: RUSTPYTHON
def test_release_save_unacquired(self):
return super().test_release_save_unacquired()

@unittest.skip('TODO: RUSTPYTHON; flaky test')
def test_different_thread(self):
return super().test_different_thread()
Expand Down
2 changes: 1 addition & 1 deletion 2 crates/common/src/refcount.rs
Show comments
View file
Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ impl RefCount {
pub fn safe_inc(&self) -> bool {
let mut old = State::from_raw(self.state.load(Ordering::Relaxed));
loop {
if old.destructed() {
if old.destructed() || old.strong() == 0 {
return false;
}
if (old.strong() as usize) >= STRONG {
Expand Down
50 changes: 35 additions & 15 deletions 50 crates/compiler-core/src/bytecode.rs
Show comments
View file
Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use core::{
cell::UnsafeCell,
hash, mem,
ops::Deref,
sync::atomic::{AtomicU8, AtomicU16, Ordering},
sync::atomic::{AtomicU8, AtomicU16, AtomicUsize, Ordering},
};
use itertools::Itertools;
use malachite_bigint::BigInt;
Expand Down Expand Up @@ -411,6 +411,10 @@ impl TryFrom<&[u8]> for CodeUnit {
pub struct CodeUnits {
units: UnsafeCell<Box<[CodeUnit]>>,
adaptive_counters: Box<[AtomicU16]>,
/// Pointer-sized cache entries for descriptor pointers.
/// Single atomic load/store prevents torn reads when multiple threads
/// specialize the same instruction concurrently.
pointer_cache: Box<[AtomicUsize]>,
}

// SAFETY: All cache operations use atomic read/write instructions.
Expand All @@ -432,9 +436,15 @@ impl Clone for CodeUnits {
.iter()
.map(|c| AtomicU16::new(c.load(Ordering::Relaxed)))
.collect();
let pointer_cache = self
.pointer_cache
.iter()
.map(|c| AtomicUsize::new(c.load(Ordering::Relaxed)))
.collect();
Self {
units: UnsafeCell::new(units),
adaptive_counters,
pointer_cache,
}
}
}
Expand Down Expand Up @@ -472,13 +482,19 @@ impl<const N: usize> From<[CodeUnit; N]> for CodeUnits {
impl From<Vec<CodeUnit>> for CodeUnits {
fn from(value: Vec<CodeUnit>) -> Self {
let units = value.into_boxed_slice();
let adaptive_counters = (0..units.len())
let len = units.len();
let adaptive_counters = (0..len)
.map(|_| AtomicU16::new(0))
.collect::<Vec<_>>()
.into_boxed_slice();
let pointer_cache = (0..len)
.map(|_| AtomicUsize::new(0))
.collect::<Vec<_>>()
.into_boxed_slice();
Self {
units: UnsafeCell::new(units),
adaptive_counters,
pointer_cache,
}
}
}
Expand Down Expand Up @@ -600,25 +616,29 @@ impl CodeUnits {
lo | (hi << 16)
}

/// Write a u64 value across four consecutive CACHE code units starting at `index`.
/// Store a pointer-sized value atomically in the pointer cache at `index`.
///
/// Uses a single `AtomicUsize` store to prevent torn writes when
/// multiple threads specialize the same instruction concurrently.
///
/// # Safety
/// Same requirements as `write_cache_u16`.
pub unsafe fn write_cache_u64(&self, index: usize, value: u64) {
unsafe {
self.write_cache_u32(index, value as u32);
self.write_cache_u32(index + 2, (value >> 32) as u32);
}
/// - `index` must be in bounds.
/// - `value` must be `0` or a valid `*const PyObject` encoded as `usize`.
/// - Callers must follow the cache invalidation/upgrade protocol:
/// invalidate the version guard before writing and publish the new
/// version after writing.
pub unsafe fn write_cache_ptr(&self, index: usize, value: usize) {
self.pointer_cache[index].store(value, Ordering::Relaxed);
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Resolved

Uh oh!

There was an error while loading. Please reload this page.

}

/// Read a u64 value from four consecutive CACHE code units starting at `index`.
/// Load a pointer-sized value atomically from the pointer cache at `index`.
///
/// Uses a single `AtomicUsize` load to prevent torn reads.
///
/// # Panics
/// Panics if `index + 3` is out of bounds.
pub fn read_cache_u64(&self, index: usize) -> u64 {
let lo = self.read_cache_u32(index) as u64;
let hi = self.read_cache_u32(index + 2) as u64;
lo | (hi << 32)
/// Panics if `index` is out of bounds.
pub fn read_cache_ptr(&self, index: usize) -> usize {
self.pointer_cache[index].load(Ordering::Relaxed)
}

/// Read adaptive counter bits for instruction at `index`.
Expand Down
Loading
Oops, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

Loading
Oops, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

Add this suggestion to a batch that can be applied as a single commit. This suggestion is invalid because no changes were made to the code. Suggestions cannot be applied while the pull request is closed. Suggestions cannot be applied while viewing a subset of changes. Only one suggestion per line can be applied in a batch. Add this suggestion to a batch that can be applied as a single commit. Applying suggestions on deleted lines is not supported. You must change the existing code in this line in order to create a valid suggestion. Outdated suggestions cannot be applied. This suggestion has been applied or marked resolved. Suggestions cannot be applied from pending reviews. Suggestions cannot be applied on multi-line comments. Suggestions cannot be applied while the pull request is queued to merge. Suggestion cannot be applied right now. Please check back later.
You are visitor 01402520 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.