Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions arcshift/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
## 0.4.2

Support rust 1.75 (0.4.1 regressed to require newer rust).

## 0.4.1

Support 32-bit platforms. Prior to this version, ArcShift did not provide correct information
to the allocator when deallocating heap blocks on 32-bit platforms.

## 0.4.0

`ArcShift<T>` now implements `Default` if `T:Default`.
2 changes: 1 addition & 1 deletion arcshift/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "arcshift"
version = "0.4.0"
version = "0.4.2"
documentation = "https://docs.rs/arcshift/"
homepage = "https://github.com/avl/arcshift/"
repository = "https://github.com/avl/arcshift/"
Expand Down
88 changes: 62 additions & 26 deletions arcshift/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -589,13 +589,13 @@ fn get_holder_layout<T: ?Sized>(ptr: *const T) -> Layout {
// The pointer 'ptr' is a valid pointer
let payload_layout = Layout::for_value(unsafe { &*ptr });
if is_sized::<T>() {
let layout = Layout::new::<ItemHolder<(), SizedMetadata>>();
let layout = get_holder_base_layout::<ItemHolder<(), SizedMetadata>>();
let (layout, _) = layout.extend(payload_layout).unwrap();
layout.pad_to_align()
} else {
let layout = Layout::new::<UnsizedMetadata<T>>();
let (layout, _) = layout
.extend(Layout::new::<ItemHolder<(), UnsizedMetadata<T>>>())
.extend(get_holder_base_layout::<ItemHolder<(), UnsizedMetadata<T>>>())
.unwrap();
let (layout, _) = layout.extend(payload_layout).unwrap();
layout.pad_to_align()
Expand Down Expand Up @@ -694,7 +694,7 @@ fn format_weak(weak: usize) -> std::string::String {
let count = weak & ((1 << (usize::BITS - 2)) - 1);
let have_next = (weak & WEAK_HAVE_NEXT) != 0;
let have_prev = (weak & WEAK_HAVE_PREV) != 0;
std::format!("(weak: {} prev: {} next: {})", count, have_prev, have_next)
std::format!("(weak: {count} prev: {have_prev} next: {have_next})")
}

#[allow(unused)]
Expand Down Expand Up @@ -773,15 +773,15 @@ fn make_unsized_holder_from_box<T: ?Sized>(
#[cfg(feature = "validate")]
unsafe {
addr_of_mut!((*item_holder_ptr).magic1)
.write(std::sync::atomic::AtomicU64::new(0xbeefbeefbeef8111));
.write(std::sync::atomic::AtomicUsize::new(0xbeef8111));
}

// SAFETY:
// result_ptr is a valid pointer
#[cfg(feature = "validate")]
unsafe {
addr_of_mut!((*item_holder_ptr).magic2)
.write(std::sync::atomic::AtomicU64::new(0x1234123412348111));
.write(std::sync::atomic::AtomicUsize::new(0x12348111));
}

// SAFETY:
Expand All @@ -801,14 +801,14 @@ fn make_sized_holder<T>(
let holder = ItemHolder {
the_meta: SizedMetadata,
#[cfg(feature = "validate")]
magic1: std::sync::atomic::AtomicU64::new(0xbeefbeefbeef8111),
magic1: std::sync::atomic::AtomicUsize::new(0xbeef8111),
next: Default::default(),
prev: atomic::AtomicPtr::new(prev as *mut _),
strong_count: atomic::AtomicUsize::new(1),
weak_count: atomic::AtomicUsize::new(initial_weak_count::<T>(prev)),
advance_count: atomic::AtomicUsize::new(0),
#[cfg(feature = "validate")]
magic2: std::sync::atomic::AtomicU64::new(0x1234123412348111),
magic2: std::sync::atomic::AtomicUsize::new(0x12348111),
payload: UnsafeCell::new(ManuallyDrop::new(payload)),
};

Expand Down Expand Up @@ -878,15 +878,15 @@ fn make_sized_holder_from_box<T: ?Sized>(
#[cfg(feature = "validate")]
unsafe {
addr_of_mut!((*item_holder_ptr).magic1)
.write(std::sync::atomic::AtomicU64::new(0xbeefbeefbeef8111));
.write(std::sync::atomic::AtomicUsize::new(0xbeef8111));
}

// SAFETY:
// result_ptr is a valid pointer
#[cfg(feature = "validate")]
unsafe {
addr_of_mut!((*item_holder_ptr).magic2)
.write(std::sync::atomic::AtomicU64::new(0x1234123412348111));
.write(std::sync::atomic::AtomicUsize::new(0x12348111));
}

// SAFETY:
Expand Down Expand Up @@ -977,7 +977,7 @@ Invariants:
struct ItemHolder<T: ?Sized, M: IMetadata> {
the_meta: M,
#[cfg(feature = "validate")]
magic1: std::sync::atomic::AtomicU64,
magic1: std::sync::atomic::AtomicUsize,
/// Can be incremented to keep the 'next' value alive. If 'next' is set to a new value, and
/// 'advance_count' is read as 0 after, then this node is definitely not going to advance to
/// some node *before* 'next'.
Expand All @@ -998,7 +998,7 @@ struct ItemHolder<T: ?Sized, M: IMetadata> {
/// that this won't be the last ever.
weak_count: atomic::AtomicUsize,
#[cfg(feature = "validate")]
magic2: std::sync::atomic::AtomicU64,
magic2: std::sync::atomic::AtomicUsize,

/// Pointer to the next value or null. Possibly decorated (i.e, least significant bit set)
/// The decoration determines:
Expand All @@ -1010,6 +1010,47 @@ struct ItemHolder<T: ?Sized, M: IMetadata> {
pub(crate) payload: UnsafeCell<ManuallyDrop<T>>,
}

// T is SizedMetadata or UnsizedMetadata
const fn get_holder_base_layout<T: Sized>() -> Layout {
if core::mem::size_of::<atomic::AtomicUsize>() % (core::mem::size_of::<usize>()) != 0 {
panic!("platform had unsupported size of atomic usize")
}
if core::mem::size_of::<atomic::AtomicPtr<ItemHolderDummy<T>>>()
% (core::mem::size_of::<usize>())
!= 0
{
panic!("platform had unsupported size of atomic pointers")
}
if core::mem::align_of::<atomic::AtomicUsize>() != core::mem::size_of::<usize>() {
panic!("platform had unsupported size of atomic usize")
}
if core::mem::align_of::<atomic::AtomicPtr<ItemHolderDummy<T>>>()
!= core::mem::size_of::<usize>()
{
panic!("platform had unsupported size of atomic pointers")
}

let base_size = 3 * size_of::<atomic::AtomicUsize>()
+ 2 * size_of::<atomic::AtomicPtr<ItemHolderDummy<T>>>();

#[cfg(not(feature = "validate"))]
const EXTRA_WORDS: usize = 0;
#[cfg(feature = "validate")]
const EXTRA_WORDS: usize = 2;

// SAFETY:
// repr(C) ignores zero sized types, and
// since all items have the same size and padding,
// the resulting size is just the number of elements
// times the size of each element.
unsafe {
Layout::from_size_align_unchecked(
EXTRA_WORDS * size_of::<usize>() + base_size,
core::mem::align_of::<usize>(),
)
}
}

impl<T: ?Sized, M: IMetadata> PartialEq for ItemHolder<T, M> {
#[allow(clippy::ptr_eq)] //We actually want to use addr_eq, but it's not available on older rust versions. Let's just use this for now.
fn eq(&self, other: &ItemHolder<T, M>) -> bool {
Expand Down Expand Up @@ -1270,7 +1311,7 @@ impl<T: ?Sized, M: IMetadata> ItemHolder<T, M> {

let magic1 = atomic_magic1.load(Ordering::Relaxed);
let magic2 = atomic_magic2.load(Ordering::Relaxed);
if magic1 >> 16 != 0xbeefbeefbeef {
if magic1 >> 16 != 0xbeef {
debug_println!(
"Internal error - bad magic1 in {:?}: {} ({:x})",
ptr,
Expand All @@ -1280,7 +1321,7 @@ impl<T: ?Sized, M: IMetadata> ItemHolder<T, M> {
debug_println!("Backtrace: {}", std::backtrace::Backtrace::capture());
std::process::abort();
}
if magic2 >> 16 != 0x123412341234 {
if magic2 >> 16 != 0x1234 {
debug_println!(
"Internal error - bad magic2 in {:?}: {} ({:x})",
ptr,
Expand Down Expand Up @@ -1315,9 +1356,9 @@ impl<T: ?Sized, M: IMetadata> ItemHolder<T, M> {
panic!();
}
let magic = MAGIC.fetch_add(1, Ordering::Relaxed);
let magic = magic as i64 as u64;
atomic_magic1.fetch_and(0xffff_ffff_ffff_0000, Ordering::Relaxed);
atomic_magic2.fetch_and(0xffff_ffff_ffff_0000, Ordering::Relaxed);
let magic = magic as isize as usize;
atomic_magic1.fetch_and(0xffff_0000, Ordering::Relaxed);
atomic_magic2.fetch_and(0xffff_0000, Ordering::Relaxed);
atomic_magic1.fetch_or(magic, Ordering::Relaxed);
atomic_magic2.fetch_or(magic, Ordering::Relaxed);
}
Expand Down Expand Up @@ -1637,8 +1678,7 @@ fn do_upgrade_weak<T: ?Sized, M: IMetadata>(
#[cfg(feature = "validate")]
assert!(
get_weak_count(_reduce_weak) > 1,
"assertion failed: in do_upgrade_weak(1), reduced weak {:x?} to 0",
item_ptr
"assertion failed: in do_upgrade_weak(1), reduced weak {item_ptr:x?} to 0"
);

return Some(item_ptr);
Expand Down Expand Up @@ -1890,8 +1930,7 @@ fn do_advance_strong<T: ?Sized, M: IMetadata>(
#[cfg(feature = "validate")]
assert!(
prior_strong > 0,
"strong count {:x?} must be >0, but was 0",
b
"strong count {b:x?} must be >0, but was 0"
);

// If b_strong was not 0, it had a weak count. Our increment of it above would have made it so that
Expand Down Expand Up @@ -1982,8 +2021,7 @@ fn raw_deallocate_node<T: ?Sized, M: IMetadata>(
// item_ptr is guaranteed valid by caller
unsafe { (*item_ptr).strong_count.load(Ordering::SeqCst) },
0,
"{:x?} strong count must be 0 when deallocating",
item_ptr
"{item_ptr:x?} strong count must be 0 when deallocating"
);

#[cfg(feature = "validate")]
Expand Down Expand Up @@ -2246,8 +2284,7 @@ fn do_janitor_task<T: ?Sized, M: IMetadata>(
assert_eq!(
get_weak_count(prior_item_weak_count),
1,
"{:x?} weak_count should still be 1, and we decrement it to 0",
item_ptr
"{item_ptr:x?} weak_count should still be 1, and we decrement it to 0"
);
}

Expand Down Expand Up @@ -2325,8 +2362,7 @@ fn do_janitor_task<T: ?Sized, M: IMetadata>(
assert_ne!(
new_predecessor_ptr as *const _,
null(),
"assert failed, {:?} was endptr",
new_predecessor_ptr
"assert failed, {new_predecessor_ptr:?} was endptr"
);
do_unlock(Some(new_predecessor));
debug_println!("New candidate advanced to {:x?}", cur_ptr);
Expand Down
12 changes: 6 additions & 6 deletions arcshift/src/tests/custom_fuzz.rs
Original file line number Diff line number Diff line change
Expand Up @@ -331,7 +331,7 @@ fn generic_thread_fuzzing_57() {
let statics = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "0"];

let i = 57;
println!("--- Seed {} ---", i);
println!("--- Seed {i} ---");
model(move || {
let mut rng = StdRng::seed_from_u64(i);
let mut counter = 0usize;
Expand Down Expand Up @@ -411,7 +411,7 @@ fn generic_thread_fuzzing_all_impl(seed: Option<u64>, repro: Option<&str>) {
for i in range {
model2(
move || {
println!("--- Seed {} ---", i);
println!("--- Seed {i} ---");
let mut rng = StdRng::seed_from_u64(i);
let mut counter = 0usize;
let owner = std::sync::Arc::new(SpyOwner2::new());
Expand All @@ -433,7 +433,7 @@ fn generic_thread_fuzzing_121() {
{
let i = 121;
let statics = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "0"];
println!("--- Seed {} ---", i);
println!("--- Seed {i} ---");
model(move || {
let mut rng = StdRng::seed_from_u64(i);
let mut counter = 0usize;
Expand All @@ -453,7 +453,7 @@ fn generic_thread_fuzzing_21() {
{
let i = 21;
let statics = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "0"];
println!("--- Seed {} ---", i);
println!("--- Seed {i} ---");
model(move || {
let mut rng = StdRng::seed_from_u64(i);
let mut counter = 0usize;
Expand All @@ -474,7 +474,7 @@ fn generic_thread_fuzzing_2_only() {
let i = 2;

let statics = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "0"];
println!("--- Seed {} ---", i);
println!("--- Seed {i} ---");
model(move || {
let mut rng = StdRng::seed_from_u64(i);
let mut counter = 0usize;
Expand All @@ -495,7 +495,7 @@ fn generic_thread_fuzzing_8() {
{
let i = 8;
let statics = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "0"];
println!("--- Seed {} ---", i);
println!("--- Seed {i} ---");
model(move || {
let mut rng = StdRng::seed_from_u64(i);
let mut counter = 0usize;
Expand Down
7 changes: 2 additions & 5 deletions arcshift/src/tests/race_detector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -575,10 +575,7 @@ fn generic_3threading_b_all_impl(skip1: usize, skip2: usize, skip3: usize, repro
for (_n3, op3) in ops23.iter().enumerate().skip(skip3).take(limit) {
{
println!("\n");
println!(
" ===================== {} {} {} ======================",
_n1, _n2, _n3
);
println!(" ===================== {_n1} {_n2} {_n3} ======================");
println!("\n");
}
generic_3thread_ops_b(*op1, *op2, *op3, repro)
Expand Down Expand Up @@ -649,7 +646,7 @@ fn generic_3threading_a_all_impl(skip0: usize, skip1: usize, skip2: usize) {
for (n2, op2) in ops.iter().enumerate().skip(skip1) {
for (n3, op3) in ops.iter().enumerate().skip(skip2) {
{
println!("========= {} {} {} ==========", n1, n2, n3);
println!("========= {n1} {n2} {n3} ==========");
}
generic_3thread_ops_a(*op1, *op2, *op3);
if skip0 != 0 || skip1 != 0 || skip2 != 0 {
Expand Down