Rfcs: API for retrieving Weak's base pointer

Created on 14 Oct 2018  路  4Comments  路  Source: rust-lang/rfcs

I'd like to use rc::Weak as keys in a HashMap, such that clones of the same Weak map to the same value, but clones of a different Weak don't.

A cleanup routine would clean up dead Weaks every once in a while, so as to not leak memory.

This is useful because the HashMap would be inside the Rc, actually it would be inside all of the Rcs for which it has a Weak key. To write it any other way would require rewriting everything I've done so far, so it'd seriously break API compatibility.

For this to work, I need to be able to get access to the Weak's base pointer. It could even return an &MaybeUninit\ or something, idk.

In fact it would be more useful if it did &MaybeUninit\, if the Rc also had a similar API. I have previously asked for the ability to compare an Rc and a Weak and this would provide that too.

T-libs

Most helpful comment

Even if you are only using it as an optimization, you still need to have a consistent hash function, as it is a logic error to use an inconsistent hash function with the HashMap. The base pointer would be an inconsistent hash function.

Dangling pointers are not UB, as evidenced by the fact that they can easily be created from safe rust. It's only de-referencing a dangling pointer which is undefined.

All 4 comments

You can achieve the same thing by storing the raw "live" pointer next to your Weak key, eg:

struct WeakKey<T> {
    weak: Weak<T>,
    ptr: *const T,
}

And then implement Hash and Eq to only look at the ptr field. When given a Weak key to look up, you need to convert it to a strong reference to get the pointer value, and then you can construct a WeakKey again. If the value has already been dropped at that point, then you can assume it's meaningless to try to look it up anyway.

Part of the contract of a weak pointer is that it is not supposed to be possible to distinguish a weak pointer with a strong count of zero (value dropped, but memory still allocated), from a weak pointer with a weak count of zero (memory deallocated, or never allocated in the first place) - this is important so that the weak pointer can "detach" itself from the allocated memory (potentially allowing it to be freed) without changing its value.

Exposing the "base pointer" from the weak pointer, and using that to implement Hash or Eq would violate the HashMap contract in the same way that would, because the weak pointer is allowed to nullify that base pointer at any time.

For this reason, the extra storage of ptr is actually necessary to ensure a stable hash function, even if the base pointer were exposed.

(Also note there is no unsafety here, because the raw pointer never needs to be de-referenced)

Since I'll be cleaning up dead Weaks over time, I just need the base pointer to optimize things.

Also, dangling pointers are still UB.

Even if you are only using it as an optimization, you still need to have a consistent hash function, as it is a logic error to use an inconsistent hash function with the HashMap. The base pointer would be an inconsistent hash function.

Dangling pointers are not UB, as evidenced by the fact that they can easily be created from safe rust. It's only de-referencing a dangling pointer which is undefined.

They are UB in C, at least. There's a discussion about it on internals, but I haven't read through it.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

torkleyy picture torkleyy  路  3Comments

steveklabnik picture steveklabnik  路  4Comments

mqudsi picture mqudsi  路  3Comments

3442853561 picture 3442853561  路  3Comments

rudolfschmidt picture rudolfschmidt  路  3Comments