Skip to content

Commit

Permalink
Rollup merge of #134496 - DiuDiu777:fix-doc, r=ibraheemdev
Browse files Browse the repository at this point in the history
Update documentation for Arc::from_raw, Arc::increment_strong_count, and Arc::decrement_strong_count to clarify allocator requirement

### Related Issue:
This update addresses parts of the issue raised in [#134242](#134242), where Arc's documentation lacks `Global Allocator` safety descriptions for three APIs. And this was confirmed by ```@workingjubilee``` :
> Wait, nevermind. I apparently forgot the `increment_strong_count` is implicitly A = Global. Ugh. Another reason these things are hard to track, unfortunately.

### PR Description
This PR updates the document for the following APIs:
- `Arc::from_raw`
- `Arc::increment_strong_count`
- `Arc::decrement_strong_count`

These APIs currently lack an important piece of documentation: **the raw pointer must point to a block of memory allocated by the global allocator**. This crucial detail is specified in the source code but is not reflected in the documentation, which could lead to confusion or incorrect usage by users.

### Problem:
The following example demonstrates the potential confusion caused by the lack of documentation:

```rust
#![feature(allocator_api)]
use std::alloc::{Allocator,AllocError, Layout};
use std::ptr::NonNull;
use std::sync::Arc;

struct LocalAllocator {
    memory: NonNull<u8>,
    size: usize,
}

impl LocalAllocator {
    fn new(size: usize) -> Self {
        Self {
            memory: unsafe { NonNull::new_unchecked(&mut 0u8 as *mut u8) },
            size,
        }
    }
}

unsafe impl Allocator for LocalAllocator {
    fn allocate(&self, _layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
        Ok(NonNull::slice_from_raw_parts(self.memory, self.size))
    }

    unsafe fn deallocate(&self, _ptr: NonNull<u8>, _layout: Layout) {
    }
}

fn main() {
    let allocator = LocalAllocator::new(64);
    let arc = Arc::new_in(5, &allocator); // Here, allocator could be any non-global allocator
    let ptr = Arc::into_raw(arc);

    unsafe {
        Arc::increment_strong_count(ptr);
        let arc = Arc::from_raw(ptr);
        assert_eq!(2, Arc::strong_count(&arc)); // Failed here!
    }
}
```
  • Loading branch information
matthiaskrgr authored Jan 16, 2025
2 parents fca1481 + 48e671e commit 87b3671
Showing 1 changed file with 6 additions and 2 deletions.
8 changes: 6 additions & 2 deletions library/alloc/src/sync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1397,6 +1397,8 @@ impl<T: ?Sized> Arc<T> {
/// different types. See [`mem::transmute`][transmute] for more information
/// on what restrictions apply in this case.
///
/// The raw pointer must point to a block of memory allocated by the global allocator.
///
/// The user of `from_raw` has to make sure a specific value of `T` is only
/// dropped once.
///
Expand Down Expand Up @@ -1452,7 +1454,8 @@ impl<T: ?Sized> Arc<T> {
///
/// The pointer must have been obtained through `Arc::into_raw`, and the
/// associated `Arc` instance must be valid (i.e. the strong count must be at
/// least 1) for the duration of this method.
/// least 1) for the duration of this method, and `ptr` must point to a block of memory
/// allocated by the global allocator.
///
/// # Examples
///
Expand Down Expand Up @@ -1486,7 +1489,8 @@ impl<T: ?Sized> Arc<T> {
///
/// The pointer must have been obtained through `Arc::into_raw`, and the
/// associated `Arc` instance must be valid (i.e. the strong count must be at
/// least 1) when invoking this method. This method can be used to release the final
/// least 1) when invoking this method, and `ptr` must point to a block of memory
/// allocated by the global allocator. This method can be used to release the final
/// `Arc` and backing storage, but **should not** be called after the final `Arc` has been
/// released.
///
Expand Down

0 comments on commit 87b3671

Please sign in to comment.