# Laundering pointers

**URL:** <https://internals.rust-lang.org/t/laundering-pointers/21859>\
**Category:** Uncategorized\
**Created:** [November 13, 2024, 12:04pm UTC](https://internals.rust-lang.org/t/laundering-pointers/21859 "2024-11-13T12:04:35Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![WorldSEnder](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/worldsender/32/9673_2.png) [@WorldSEnder](https://internals.rust-lang.org/u/WorldSEnder)\
**Post date:** [November 13, 2024, 12:04pm UTC](https://internals.rust-lang.org/t/laundering-pointers/21859/1 "2024-11-13T12:04:35Z")

</div>

First, the setup for this experiment, assume

```rust
type Foo; // Not really super important, just some data.
struct Forum(*mut [Foo]);
impl Forum {
    pub fn get_mut(&mut self) -> &mut [Foo];
}

```

The code I want to dissect now looks like this:

```rust
let mut place: Forum = todo!(); /* constructed externally */
let p = derive(place.get_mut()); // 1
modify(place.get_mut()); // 2
reuse(p); // 3

```

First, we `derive` a location of interest in the collection of `Foo`s. For our dummy example, this function looks like

```rust
fn derive(p: &mut [Foo]) -> *mut Foo {
    std::ptr::from_mut(&mut p[1337]) // index 1337 is interesting indeed
}

```

but in reality, the index is not necessarily as simple as a single number. The main point is that I don't want to remember this index in the return value. I compute it based on user input and some other stuff, then traverse the `Forum` with it (which also is more tree-like than the simple array here). I finally land on a single "interesting" item that I know will still be there later.

Second, we "modify" the forum. The details of this method are not important, it merely needs to get passed a `&mut [Foo]` and make use of it somehow (without structurally changing it)

```rust
fn modify(p: &mut [Foo]);

```

Third and finally, `reuse` contains the important point of this post:

```rust
fn reuse(p: *mut Foo) {
    //let p = launder(p); //????
    let r = unsafe { &mut *p };
    println!("{:?}", *r);
}

```

I want to use the pointer to the interesting index. But `miri` informs me that this is forbidden by stacked-borrow rules ([Playground](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=f6c295976e88952c4737cabc6c6b73df))

> that tag does not exist in the borrow stack for this location

I agree with this. The initial borrow passed to `derive` gets replaced by the borrow passed to `modify` which seems to make basically any pointer-based write access to an item invalid. The question is now to fix this?

- Approach 1: Use `RefCell` to access the items? I would have to rewrite everything in `derive` and `modify` to work with an immutable ref to the `Forum`, take a `&RefCell<Foo>` into `reuse` and borrow it there. While most likely the _safest_ of the option, this has considerable overhead in both restructuring and the refcells. I would like to avoid this.

- Approach 2: Chance `derive` to work on a "more powerful" view of the data. Instead of getting a `&mut [Foo]` which reborrows from the pointer in `Forum`, one could use the `*mut [Foo]` directly to derive the "interesting" place. I would think that this thusly derived pointer would not get popped off the borrow stack with the second borrow in `modify`, "surviving" the modifications and could then be used in `reuse`.

- Approach 3: Pointer laundering. C++ has the delightful method `std::launder`, which returns takes a pointer and returns it unharmed. The user can e.g. say "there used to be an object here, there is now an object here, but it might be a different one. Please let me access it through this pointer".

- Approach 4: ??? Ideas and comments are appreciated, maybe I'm just missing something straight-forward.

---

<div class="post-metadata">

**Author:** ![steffahn](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/steffahn/32/13288_2.png) [@steffahn](https://internals.rust-lang.org/u/steffahn)\
**Post date:** [November 13, 2024, 12:07pm UTC](https://internals.rust-lang.org/t/laundering-pointers/21859/2 "2024-11-13T12:07:52Z")

</div>

I think, this kind of thread would be a better fit for [users.rust-lang.org](http://users.rust-lang.org) rather than the internals forum.

---

<div class="post-metadata">

**Author:** ![WorldSEnder](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/worldsender/32/9673_2.png) [@WorldSEnder](https://internals.rust-lang.org/u/WorldSEnder)\
**Post date:** [November 13, 2024, 12:10pm UTC](https://internals.rust-lang.org/t/laundering-pointers/21859/3 "2024-11-13T12:10:48Z")

</div>

I posted in here because Approach 3 mentions an operation that does currently not exist, but I think should. (Can I move it? Feel free to)

---

<div class="post-metadata">

**Author:** ![bjorn3](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/bjorn3/32/2736_2.png) [@bjorn3](https://internals.rust-lang.org/u/bjorn3)\
**Post date:** [November 13, 2024, 12:31pm UTC](https://internals.rust-lang.org/t/laundering-pointers/21859/4 "2024-11-13T12:31:41Z")

</div>

For pointer laundering see also:

> <https://github.com/rust-lang/unsafe-code-guidelines/issues/480>
>
> Alice Ryhl \[brings up\](https://rust-lang.zulipchat.com/#narrow/stream/136281-t-o…psem/topic/Choosing.20provenance.20exposed.20in.20the.20future.3F) the following data structure: a concurrent stack where all elements can only be popped at once.
> 
> Stack declaration:
> \`\`\`rust
> static STACK\_TOP: AtomicPtr\<Elem\>;
> 
> struct Elem {
> next: \*mut Elem,
> }
> \`\`\`
> Push:
> \`\`\`rust
> let elem = malloc();
> elem.next = STACK\_TOP.load(Acquire);
> while let Err(new\_next) = STACK\_TOP.cas(elem.next, elem, AcqRel) {
> elem.next = new\_next;
> }
> \`\`\`
> Pop all:
> \`\`\`rust
> let next = STACK\_TOP.swap(null);
> while !next.is\_null() {
> let curr = next;
> next = curr.next;
> use(curr);
> free(curr);
> }
> \`\`\`
> This can run into ABA situations in push if, between the \`load\` and the \`cas\`, the stack gets popped, freed, new elements get pushed, and they re-use the same address. Then \`STACK\_TOP\` will contain an \`Elem\` whose \`next\` points to the right element but still uses the provenance of the old element. Adding any code between the \`load\` and the \`cas\` cannot fix this since the new element might bet allocated after all of that code runs, and \`from\_exposed\_addr\` cannot "grab" a provenance that does not even exist yet.
> 
> IMO what should be done here is that \`next\` should be declared to have type \`usize\`, and one just passes the pointers through exposed\_addr/from\_exposed\_addr when they enter/leave the stack. However some people seem to consider it very important that the stack uses a normal pointer type and can be used in the rest of the code without being aware that there are concurrency shenanigans going on. I am not sure why that is so important, given in particular that I think this will at best be an utter nightmare to specify, but here are some options I have seen or thought of:
> 
> 1. I have seen a proposal to fix this for C++ with some sot of operation that "refreshes the provenance of a pointer and every other pointer reachable through it". That operation sounds like a nightmare for program verification since it can change state that is very far away from where that operation happens; we don't currently have \*any\* operation that reaches transitively through pointers and I think that kind of locality is important.
> 2. Make it so that \`from\_exposed\_addr\` actually works here. For instance, rather than angelically guessing the provenance when \`from\_exposed\_addr\` get called, we could generate a fresh \*symbolic\* provenance and gather constraints on how that provenance is used, and then raise UB when the constraints become unsatisfiable. (This is basically the "udi" part of PNVI-ae-udi.) Unfortunately I have no great idea how to do this with a complex aliasing model.
> 3. Introduce a kind of provenance that has the following effect: when doing a load through a pointer with such provenance, all provenance that was loaded is refreshed by passing the pointer through \`|p| from\_exposed\_addr(p.exposed\_addr())\`, and the loaded provenance also recursively obtains this effect. However, now loads through such pointers cannot be DCE'd, since they have the side-effect of exposing some provenance, so this doesn't seem practical either.
> 
> So to me (2) is the only realistic option I have seen so far -- which conveniently would also get rid of angelic choice again, if we can make it work...

---

<div class="post-metadata">

**Author:** ![steffahn](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/steffahn/32/13288_2.png) [@steffahn](https://internals.rust-lang.org/u/steffahn)\
**Post date:** [May 7, 2026, 12:32pm UTC](https://internals.rust-lang.org/t/laundering-pointers/21859/5 "2026-05-07T12:32:09Z")

</div>

Closed on May 7, 2026, 12:32pm UTC

This topic was automatically closed 540 days after the last reply. New replies are no longer allowed.
