From 9afb0c9e08c880240f1ebe8e1c195494bdd1651b Mon Sep 17 00:00:00 2001 From: Anders Musikka Date: Sat, 2 Aug 2025 01:39:45 +0200 Subject: [PATCH 1/6] support 32-bit platforms --- arcshift/CHANGELOG.md | 5 +++ arcshift/src/lib.rs | 73 ++++++++++++++++++++++++++++++++++--------- 2 files changed, 63 insertions(+), 15 deletions(-) diff --git a/arcshift/CHANGELOG.md b/arcshift/CHANGELOG.md index 6763eaa..5a042ff 100644 --- a/arcshift/CHANGELOG.md +++ b/arcshift/CHANGELOG.md @@ -1,3 +1,8 @@ +## 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/src/lib.rs b/arcshift/src/lib.rs index 4debab6..0703688 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() @@ -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,49 @@ struct ItemHolder { pub(crate) payload: UnsafeCell>, } +// T is SizedMetadata or UnsizedMetadata +const fn get_holder_base_layout() -> Layout { + const { + if !size_of::().is_multiple_of(size_of::()) + { + panic!("platform had unsupported size of atomic usize") + } + if !size_of::>>().is_multiple_of(size_of::()) + { + panic!("platform had unsupported size of atomic pointers") + } + if align_of::() != size_of::() + { + panic!("platform had unsupported size of atomic usize") + } + if align_of::>>() != 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, + 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 +1313,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 +1323,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 +1358,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); } From ea3d5f3adda57956ed869660444e4192b86c7470 Mon Sep 17 00:00:00 2001 From: Anders Musikka Date: Sat, 2 Aug 2025 01:41:03 +0200 Subject: [PATCH 2/6] Clipypy fixes --- arcshift/src/lib.rs | 4 ++-- arcshift/src/tests/custom_fuzz.rs | 12 ++++++------ arcshift/src/tests/race_detector.rs | 5 ++--- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/arcshift/src/lib.rs b/arcshift/src/lib.rs index 0703688..b725706 100644 --- a/arcshift/src/lib.rs +++ b/arcshift/src/lib.rs @@ -1013,11 +1013,11 @@ struct ItemHolder { // T is SizedMetadata or UnsizedMetadata const fn get_holder_base_layout() -> Layout { const { - if !size_of::().is_multiple_of(size_of::()) + if size_of::() % (size_of::()) != 0 { panic!("platform had unsupported size of atomic usize") } - if !size_of::>>().is_multiple_of(size_of::()) + if size_of::>>() % (size_of::()) != 0 { panic!("platform had unsupported size of atomic pointers") } 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..96a13f0 100644 --- a/arcshift/src/tests/race_detector.rs +++ b/arcshift/src/tests/race_detector.rs @@ -576,8 +576,7 @@ fn generic_3threading_b_all_impl(skip1: usize, skip2: usize, skip3: usize, repro { println!("\n"); println!( - " ===================== {} {} {} ======================", - _n1, _n2, _n3 + " ===================== {_n1} {_n2} {_n3} ======================" ); println!("\n"); } @@ -649,7 +648,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 { From cc8e70a977e0e9a52ac6148c1064647bd81035ac Mon Sep 17 00:00:00 2001 From: Anders Musikka Date: Sat, 2 Aug 2025 01:43:03 +0200 Subject: [PATCH 3/6] Fmt --- arcshift/src/lib.rs | 23 +++++++++-------------- arcshift/src/tests/race_detector.rs | 4 +--- 2 files changed, 10 insertions(+), 17 deletions(-) diff --git a/arcshift/src/lib.rs b/arcshift/src/lib.rs index b725706..fd0b14e 100644 --- a/arcshift/src/lib.rs +++ b/arcshift/src/lib.rs @@ -1011,28 +1011,24 @@ struct ItemHolder { } // T is SizedMetadata or UnsizedMetadata -const fn get_holder_base_layout() -> Layout { +const fn get_holder_base_layout() -> Layout { const { - if size_of::() % (size_of::()) != 0 - { + if size_of::() % (size_of::()) != 0 { panic!("platform had unsupported size of atomic usize") } - if size_of::>>() % (size_of::()) != 0 - { + if size_of::>>() % (size_of::()) != 0 { panic!("platform had unsupported size of atomic pointers") } - if align_of::() != size_of::() - { + if align_of::() != size_of::() { panic!("platform had unsupported size of atomic usize") } - if align_of::>>() != size_of::() - { + if align_of::>>() != size_of::() { panic!("platform had unsupported size of atomic pointers") } } - let base_size = 3*size_of::() - +2*size_of::>>(); + let base_size = 3 * size_of::() + + 2 * size_of::>>(); #[cfg(not(feature = "validate"))] const EXTRA_WORDS: usize = 0; @@ -1045,10 +1041,9 @@ const fn get_holder_base_layout() -> Layout { // 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, - align_of::() + EXTRA_WORDS * size_of::() + base_size, + align_of::(), ) } } diff --git a/arcshift/src/tests/race_detector.rs b/arcshift/src/tests/race_detector.rs index 96a13f0..3897f4b 100644 --- a/arcshift/src/tests/race_detector.rs +++ b/arcshift/src/tests/race_detector.rs @@ -575,9 +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) From c4ebb6ef7f4e74dbf6df26b115df631d2c37bd1b Mon Sep 17 00:00:00 2001 From: Anders Musikka Date: Sat, 2 Aug 2025 01:44:22 +0200 Subject: [PATCH 4/6] More clippy fixes --- arcshift/src/lib.rs | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/arcshift/src/lib.rs b/arcshift/src/lib.rs index fd0b14e..635ff64 100644 --- a/arcshift/src/lib.rs +++ b/arcshift/src/lib.rs @@ -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)] @@ -1675,8 +1675,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); @@ -1928,8 +1927,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 @@ -2020,8 +2018,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")] @@ -2284,8 +2281,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" ); } @@ -2363,8 +2359,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); From 5f24a07214a641ad818414fc5904689efec02bee Mon Sep 17 00:00:00 2001 From: Anders Musikka Date: Sat, 2 Aug 2025 01:45:14 +0200 Subject: [PATCH 5/6] Step version number --- arcshift/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arcshift/Cargo.toml b/arcshift/Cargo.toml index 46bc23c..8952dd4 100644 --- a/arcshift/Cargo.toml +++ b/arcshift/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "arcshift" -version = "0.4.0" +version = "0.4.1" documentation = "https://docs.rs/arcshift/" homepage = "https://github.com/avl/arcshift/" repository = "https://github.com/avl/arcshift/" From 611e087c51c87a73383eec5203d18f8dcd4fce9f Mon Sep 17 00:00:00 2001 From: Anders Musikka Date: Sat, 2 Aug 2025 01:52:33 +0200 Subject: [PATCH 6/6] Support 1.75 --- arcshift/CHANGELOG.md | 4 ++++ arcshift/Cargo.toml | 2 +- arcshift/src/lib.rs | 31 +++++++++++++++++-------------- 3 files changed, 22 insertions(+), 15 deletions(-) diff --git a/arcshift/CHANGELOG.md b/arcshift/CHANGELOG.md index 5a042ff..b5a810f 100644 --- a/arcshift/CHANGELOG.md +++ b/arcshift/CHANGELOG.md @@ -1,3 +1,7 @@ +## 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 diff --git a/arcshift/Cargo.toml b/arcshift/Cargo.toml index 8952dd4..3b79c91 100644 --- a/arcshift/Cargo.toml +++ b/arcshift/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "arcshift" -version = "0.4.1" +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 635ff64..b93205f 100644 --- a/arcshift/src/lib.rs +++ b/arcshift/src/lib.rs @@ -1012,19 +1012,22 @@ struct ItemHolder { // T is SizedMetadata or UnsizedMetadata const fn get_holder_base_layout() -> Layout { - const { - if size_of::() % (size_of::()) != 0 { - panic!("platform had unsupported size of atomic usize") - } - if size_of::>>() % (size_of::()) != 0 { - panic!("platform had unsupported size of atomic pointers") - } - if align_of::() != size_of::() { - panic!("platform had unsupported size of atomic usize") - } - if align_of::>>() != size_of::() { - panic!("platform had unsupported size of atomic pointers") - } + 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::() @@ -1043,7 +1046,7 @@ const fn get_holder_base_layout() -> Layout { unsafe { Layout::from_size_align_unchecked( EXTRA_WORDS * size_of::() + base_size, - align_of::(), + core::mem::align_of::(), ) } }