External Publication
Visit Post

Reducing Raw Pointer Footguns: Preventing Reference Aliasing Violations at Compile Time

Rust Internals [Unofficial] May 16, 2026
Source

Here's how all your AliasingGuardMut can be written with simply a &mut reference without raw pointers! So while AliasingGuardMut may be safer than using raw pointers, it doesn't seem to enable anything that &mut references can do, So where is the actual benefit of using AliasingGuardMut? Note that in your examples there were even examples of unsoundness and reference aliasing violation where I left a comment on, so AliasingGuardMut seem to not even prevent them.

fn a(b: &mut Vec<i32>) {
    *b = vec![1];
}

// some other code that must take pointer
// eg FFI code, low level code that takes pointer
// or 3rd party library code that takes pointer
fn b(b: *mut Vec<i32>) {
    unsafe { *b = vec![1] }
}

fn main() {
    let mut s = vec![1, 2, 3];

    let reff = &mut s;
    a(reff);
    b(reff);
}



    guard: &'a mut i32
}

impl<'a> Holder<'a> {
    fn write(&mut self, val: i32) {
        *self.guard = val;
    }
}

fn main() {
    let mut x = 5;

    let mut h = Holder {
        guard: &mut x,
    };

    let r = &mut *h.guard;

    h.write(10);

    *r += 1;
}



struct Arena<'a, T> {
    guard: &'a mut T,
}

impl<'a, T> Arena<'a, T> {
    fn get_mut(&self) -> &mut T {
        // This is a compile time error.
        // I hope the existing self.guard.mutable_reference() was a compile time error too
        // or it would have been unsound (worse than a raw pointer because it didn't even require unsafe!)
        &mut *self.guard
    }
}

fn main() {
    let mut value = String::from("hello");

    let mut arena = Arena {
        guard: &mut value,
    };

    let a = arena.get_mut();

    let b = arena.get_mut();

    a.push_str(" world");
    b.push_str(" !!!");
}



use std::ptr::NonNull;

struct Node {
    next: Option<NonNull<Node>>,
    value: i32,
}

struct List<'a> {
    head: Option<NonNull<Node>>,
    guard: Option<&'a mut Node>,
}

impl<'a> List<'a> {
    fn new() -> Self {
        Self {
            head: None,
            guard: None,
        }
    }

    unsafe fn push_front(&mut self, node: &'a mut Node) {
        node.next = self.head;
        self.head = Some(NonNull::from(&mut *node));
        // Note that both the new and the old code invalidate the pointer in `self.head`
        // I'm not sure how you intended to use it, but it shows that AliasingGuardMut also has footguns
        // self.guard = Some(AliasingGuardMut::from_reference(node));
        self.guard = Some(node);
    }

    fn first_mut(&mut self) -> Option<&mut Node> {
        self.guard.as_mut()
    }
}

fn increment(node: &mut Node) {
    node.value += 1;
}

fn main() {
    let mut node = Box::new(Node {
        next: None,
        value: 10,
    });

    let mut list = List::new();

    unsafe {
        list.push_front(&mut *node);
    }

    let a = list.first_mut().unwrap();

    increment(a);

    let b = list.first_mut().unwrap();

    b.value += 10;

    println!("{}", a.value);
}



struct Buffer<'a> {
    guard: &'a mut Vec<i32>,
}

impl<'a> Buffer<'a> {
    fn new(vec: &'a mut Vec<i32>) -> Self {
        Self {
            guard: vec,
        }
    }

    fn get_mut(&mut self) -> &mut Vec<i32> {
        &mut *self.guard
    }
}

fn append_data(vec: &mut Vec<i32>) {
    vec.push(100);
}

fn main() {
    let mut data = vec![1, 2, 3];

    let mut buffer = Buffer::new(&mut data);

    let a = buffer.get_mut();

    append_data(a);

    let b = buffer.get_mut();

    b.push(200);

    a.push(300);

    println!("{:?}", a);
}



struct SlotMap<'a, T> {
    slot: Option<&'a mut T>,
}

impl<'a, T> SlotMap<'a, T> {
    fn new() -> Self {
        Self {
            slot: None,
        }
    }

    fn insert(&mut self, value: &'a mut T) {
        self.slot = Some(value);
    }

    fn get_mut(&mut self, _: usize) -> &mut T {
        self.slot
            .as_mut()
            .unwrap()
    }
}

fn update_user(user: &mut String) {
    user.push_str(" updated");
}

fn main() {
    let mut user = String::from("alice");

    let mut map = SlotMap::new();

    map.insert(&mut user);

    let current = map.get_mut(0);

    update_user(current);

    let another = map.get_mut(0);

    another.push_str(" !!!");

    println!("{}", current);
}

Discussion in the ATmosphere

Loading comments...