Change:
} } <del> /// Create an `Arc<[T]>` by reusing the underlying memory /// of a `Vec<T>`. This will return the vector if the existing allocation /// is not large enough. #[cfg(not(no_global_oom_handling))] fn try_from_vec_in_place(mut v: Vec<T>) -> Result<Arc<[T]>, Vec<T>> { let layout_elements = Layout::array::<T>(v.len()).unwrap(); let layout_allocation = Layout::array::<T>(v.capacity()).unwrap(); let layout_arcinner = arcinner_layout_for_value_layout(layout_elements); let mut ptr = NonNull::new(v.as_mut_ptr()).expect("`Vec<T>` stores `NonNull<T>`"); if layout_arcinner.size() > layout_allocation.size() || layout_arcinner.align() > layout_allocation.align() { // Can't fit - calling `grow` would involve `realloc` // (which copies the elements), followed by copying again. return Err(v); } if layout_arcinner.size() < layout_allocation.size() || layout_arcinner.align() < layout_allocation.align() { // We need to shrink the allocation so that it fits // https://doc.rust-lang.org/nightly/std/alloc/trait.Allocator.html#memory-fitting // SAFETY: // - Vec allocates by requesting `Layout::array::<T>(capacity)`, so this capacity matches // - `layout_arcinner` is smaller // If this fails, the ownership has not been transferred if let Ok(p) = unsafe { Global.shrink(ptr.cast(), layout_allocation, layout_arcinner) } { ptr = p.cast(); } else { return Err(v); } } // Make sure the vec's memory isn't deallocated now let v = mem::ManuallyDrop::new(v); let ptr: *mut ArcInner<[T]> = ptr::slice_from_raw_parts_mut(ptr.as_ptr(), v.len()) as _; unsafe { ptr::copy(ptr.cast::<T>(), &mut (*ptr).data as *mut [T] as *mut T, v.len()); ptr::write(&mut (*ptr).strong, atomic::AtomicUsize::new(1)); ptr::write(&mut (*ptr).weak, atomic::AtomicUsize::new(1)); Ok(Self::from_ptr(ptr)) } } </del> /// Constructs an `Arc<[T]>` from an iterator known to be of a certain size. /// /// Behavior is undefined should the size be wrong.

Discussion:
Miri reports UB in the new test: On first sight, the error seems legitimate. That test got in Cc
Probably what happens is that in Miri, will always move the data to a new location, and then the way the test checks whether that happened causes UB. You should not call unless you are already 100% sure that both pointer point to the same allocation -- and in this case, you cannot be sure of that, since allocators do not promise that keeps the same allocation. In fact, it might be the case that even if keeps the data in-place, the allocation has a new provenance -- it is considered a new allocation at the same location, but all old pointers are invalid now and must be 'refreshed'. So this code probably has UB even if keeps the allocation in-place. I recall this was discussed somewhere at some point, and I think the C standard contains wording along these lines, but I forgot the details... Cc The fix is easy -- just do and later compare that with . The test will still fail in Miri though, and in other allocators that do not shrink in-place.
Yeah, the C standard is quite explicit about this, so for now we should follow suit. Opened
Might it be a good idea to the pointer comparison itself, so that Miri can check the actual implementation, even if it can't check the final assertion. I did suspect that other platforms might not have this behaviour - seems to show this. It might be best to feature gate the test and opt to only platforms with allocators that work like this.
Yes, but to be clear there are two bugs here: the test can fail in some platforms, such as Miri, when realloc doesn't shrink in-place the test has UB on all platforms because the two pointers are into different allocations (realloc conceptually creates a new allocation, even if it remains in-place), but is explicitly documented to only work on pointers within the same allocation
Is the comparison still UB? I'm currently working on a patch that Uses the cast for comparison Turns off this feature for non-GNU targets (since that's the only one I know for sure has the shrink-in-place behaviour) Disables the test on non GNU, and the comparison itself on Miri With that in mnd though, I'm wondering if this opt should just be removed entirely.

The perf wins I got in testing were pretty small for the amount of maintenance headache this seems likely to cause
returns regular integers, you can compare them in whatever way you want.