# Rc is unsafe \[mostly on 32-bit targets\] due to overflow

**URL:** <https://internals.rust-lang.org/t/rc-is-unsafe-mostly-on-32-bit-targets-due-to-overflow/2120>\
**Category:** Uncategorized\
**Created:** [May 23, 2015, 10:34pm UTC](https://internals.rust-lang.org/t/rc-is-unsafe-mostly-on-32-bit-targets-due-to-overflow/2120 "2015-05-23T22:34:23Z")\
**Posts on this page:** 1\
**Showing post:** 17

<div class="post-metadata">

**Author:** ![dgrunwald](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/dgrunwald/32/3667_2.png) [@dgrunwald](https://internals.rust-lang.org/u/dgrunwald)\
**Post date:** [May 24, 2015, 2:50pm UTC](https://internals.rust-lang.org/t/rc-is-unsafe-mostly-on-32-bit-targets-due-to-overflow/2120/17 "2015-05-24T14:50:40Z")

</div>

Yes, the ideal solution is to introduce a new guarantee: safe rust code will either run the destructor or leak the memory when “forgetting” a value, so that the number of “live” values always fits into `usize` (except when `sizeof(Value) == 0`).

But `mem::forget` is being used by unsafe code that needs to avoid Drop being called (e.g. because ownership of the underlying resource is moved from Rust to C code). Just last week I deleted the `unsafe` block around one of those calls, since it was producing the “unnecessary unsafe block” warning.

@glaebhoerl: I don’t think silently breaking my code by introducing an artificial memory leak in `mem::forget` is the solution here – it’s strictly worse than breaking my code by marking `mem::forget` as unsafe and making me add back the unsafe block.

In fact, grepping for `mem::forget` in `vec.rs` is quite instructive in seeing the valid use-cases of `mem::forget`:

- Forgetting `self` in order to suppress the `Drop` impl and transferring ownership (e.g. `Vec::into_iter()`)
- Forgetting a value after making an unsafe copy using `ptr::read`
- Forgetting zero-sized values in `Vec::push`, since they can be re-created from thin air later.

We’d need to formulate a guarantee that types like `Rc` can rely on while still allowing all of those uses in unsafe code.

So I see two main solutions here:

1. Introduce the new guarantee, and make `mem::forget` unsafe. This is a breaking change, but how much code would really break? I’d expect most callers to still have the `unsafe` block around `mem::forget` calls, since it hasn’t been safe for all that long. On the other hand, a new guarantee means it’s one more thing to check when reviewing unsafe code. Writing unsafe Rust code is already more difficult than writing C code due to the number of (often poorly-documented) invariants you need to uphold. How much more do we want to add to this burden?

2. Make `Rc` check for overflows. The expected performance cost on 64-bit platforms is extremely low / often zero – we just have to inhibit some optimizations to prevent overflows from being possible. On 32-bit there’s going to be a real cost, though probably not as bad as I initially thought.

If this were pre-1.0, I’d prefer option 1. Not sure now… this _is_ a safety hole, and we’ve reserved the right to make breaking changes in these cases… but on the other hand, a fix without breaking changes should be the preferred solution in post-1.0 world. I guess we need more data to decide properly: a) How much code is going to break if we make `mem::forget` unsafe again? b) How big is the impact of overflow checks, both on performance and code-size?

---

_[View the full topic](https://internals.rust-lang.org/t/rc-is-unsafe-mostly-on-32-bit-targets-due-to-overflow/2120)._
