Skip to content

(Mostly) safe manually-freed shared pointers in Rust

License

Apache-2.0, MIT licenses found

Licenses found

Apache-2.0
LICENSE-APACHE
MIT
LICENSE-MIT
Notifications You must be signed in to change notification settings

nyanpasu64/alias-ptr

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

21 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

AliasPtr – (mostly) safe shared pointers in Rust

The alias-ptr crate supplies the AliasPtr type, which allows safely creating multiple pointers to the same heap-allocated memory, and (unsafely) freeing the memory without reference counting overhead.

The AliasPtr type is a pointer whose API is modeled after Rc or Arc (providing shared Deref access to its target). Unlike them, AliasPtr expects the user to delete the target manually (an unsafe operation). This is designed to work like C++'s raw pointers, which allow aliased access to underlying data, as well as manually freeing/deleting memory.

This is not designed to replace usage of Rust's safe abstractions like Box, but to serve as a fallback where multiple ownership is necessary (and cannot be easily worked around) but the overhead of Rc or Arc is undesired. The intended use is to use AliasPtr within your data structures as if it were a Rc, carefully audit your unsafe Drop logic to ensure you never use-after-free, and expose a safe API to users.

For example, AliasPtr can be used to build a sound alternative to owning_ref::BoxRef's usage of a Box aliased with a *const (which is unsound under Stacked Borrows, fails Miri, and may miscompile once rustc enables noalias for mutable pointers). However, since BoxRef is merely a type alias of owning_ref::OwningRef, which is generic over the owning type (the reference is always a *const), changing BoxRef<T> to use an AliasPtr<T> rather than Box<T> breaks library users which expect BoxRef<T> to be the same type as OwningRef<Box<T>, T>.

Interestingly, owning-ref's VecRef type is not unsound because Vec is currently guaranteed to not invalidate references to its elements when moved (Vec will not use noalias). See "Aliasing rules for Vec<T> and other standard containers".

Install

alias-ptr is planned to be published at https://lib.rs/alias-ptr.

Docs will be located at https://docs.rs/alias-ptr.

Usage

use alias_ptr::AliasPtr;
use std::cell::Cell;

struct AliasedPair(AliasPtr<Cell<i32>>, AliasPtr<Cell<i32>>);

impl AliasedPair {
    fn new(x: i32) -> AliasedPair {
        let x = AliasPtr::new(Cell::new(x));
        AliasedPair(x.copy(), x)
    }
}

impl Drop for AliasedPair {
    fn drop(&mut self) {
        unsafe {
            self.0.delete();
        }
    }
}

#[test]
fn test_aliased_pair() {
    let pair = AliasedPair::new(1);
    pair.0.set(42);
    assert_eq!(pair.1.get(), 42);
}

Design

AliasPtr holds raw pointers rather than references (since Miri prohibits passing references into Box::from_raw()), and lends out shared references whenever dereferenced.

Testing

AliasPtr is designed to be sound under Stacked Borrows, pass Miri with Stacked Borrows enabled, and not miscompile once rustc enables mutable noalias.

To verify it passes Miri, run:

cargo +nightly miri test --target-dir miri

Note that this clobbers the "miri" subdirectory.

Credits

Thanks to those in the Rust community Discord server's #black-magic channel for discussing the various forms of UB I had to avoid while writing this crate.

About

(Mostly) safe manually-freed shared pointers in Rust

Resources

License

Apache-2.0, MIT licenses found

Licenses found

Apache-2.0
LICENSE-APACHE
MIT
LICENSE-MIT

Stars

Watchers

Forks

Packages

No packages published

Languages