diff --git a/arcshift/CHANGELOG.md b/arcshift/CHANGELOG.md index 6763eaa..b5a810f 100644 --- a/arcshift/CHANGELOG.md +++ b/arcshift/CHANGELOG.md @@ -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` now implements `Default` if `T:Default`. diff --git a/arcshift/Cargo.toml b/arcshift/Cargo.toml index 46bc23c..3b79c91 100644 --- a/arcshift/Cargo.toml +++ b/arcshift/Cargo.toml @@ -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/" diff --git a/arcshift/src/lib.rs b/arcshift/src/lib.rs index 4debab6..b93205f 100644 --- a/arcshift/src/lib.rs +++ b/arcshift/src/lib.rs @@ -589,13 +589,13 @@ fn get_holder_layout(ptr: *const T) -> Layout { // The pointer 'ptr' is a valid pointer let payload_layout = Layout::for_value(unsafe { &*ptr }); if is_sized::() { - let layout = Layout::new::>(); + let layout = get_holder_base_layout::>(); let (layout, _) = layout.extend(payload_layout).unwrap(); layout.pad_to_align() } else { let layout = Layout::new::>(); let (layout, _) = layout - .extend(Layout::new::>>()) + .extend(get_holder_base_layout::>>()) .unwrap(); let (layout, _) = layout.extend(payload_layout).unwrap(); layout.pad_to_align() @@ -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)] @@ -773,7 +773,7 @@ fn make_unsized_holder_from_box( #[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: @@ -781,7 +781,7 @@ fn make_unsized_holder_from_box( #[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: @@ -801,14 +801,14 @@ fn make_sized_holder( 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::(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)), }; @@ -878,7 +878,7 @@ fn make_sized_holder_from_box( #[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: @@ -886,7 +886,7 @@ fn make_sized_holder_from_box( #[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: @@ -977,7 +977,7 @@ Invariants: struct ItemHolder { 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'. @@ -998,7 +998,7 @@ struct ItemHolder { /// 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: @@ -1010,6 +1010,47 @@ struct ItemHolder { pub(crate) payload: UnsafeCell>, } +// T is SizedMetadata or UnsizedMetadata +const fn get_holder_base_layout() -> Layout { + if core::mem::size_of::() % (core::mem::size_of::()) != 0 { + panic!("platform had unsupported size of atomic usize") + } + if core::mem::size_of::>>() + % (core::mem::size_of::()) + != 0 + { + panic!("platform had unsupported size of atomic pointers") + } + if core::mem::align_of::() != core::mem::size_of::() { + panic!("platform had unsupported size of atomic usize") + } + if core::mem::align_of::>>() + != core::mem::size_of::() + { + panic!("platform had unsupported size of atomic pointers") + } + + let base_size = 3 * size_of::() + + 2 * size_of::>>(); + + #[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::() + base_size, + core::mem::align_of::(), + ) + } +} + impl PartialEq for ItemHolder { #[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) -> bool { @@ -1270,7 +1311,7 @@ impl ItemHolder { 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, @@ -1280,7 +1321,7 @@ impl ItemHolder { 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, @@ -1315,9 +1356,9 @@ impl ItemHolder { 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); } @@ -1637,8 +1678,7 @@ fn do_upgrade_weak( #[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); @@ -1890,8 +1930,7 @@ fn do_advance_strong( #[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 @@ -1982,8 +2021,7 @@ fn raw_deallocate_node( // 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")] @@ -2246,8 +2284,7 @@ fn do_janitor_task( 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" ); } @@ -2325,8 +2362,7 @@ fn do_janitor_task( 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); diff --git a/arcshift/src/tests/custom_fuzz.rs b/arcshift/src/tests/custom_fuzz.rs index ef025ef..7a520fc 100644 --- a/arcshift/src/tests/custom_fuzz.rs +++ b/arcshift/src/tests/custom_fuzz.rs @@ -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; @@ -411,7 +411,7 @@ fn generic_thread_fuzzing_all_impl(seed: Option, 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()); @@ -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; @@ -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; @@ -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; @@ -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; diff --git a/arcshift/src/tests/race_detector.rs b/arcshift/src/tests/race_detector.rs index 951d529..3897f4b 100644 --- a/arcshift/src/tests/race_detector.rs +++ b/arcshift/src/tests/race_detector.rs @@ -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) @@ -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 {