Join GitHub today
GitHub is home to over 31 million developers working together to host and review code, manage projects, and build software together.
Sign upPotential RefCell unsafety due to mem::forget #25841
Comments
This comment has been minimized.
This comment has been minimized.
|
Good catch! (I wonder if this applies to cc https://internals.rust-lang.org/t/rc-is-unsafe-mostly-on-32-bit-targets-due-to-overflow/2120 |
This comment has been minimized.
This comment has been minimized.
|
This case seems relatively easy to fix, since there are no threading complications -- saturating add (and checking for max before decrementing) is certainly one option. |
This comment has been minimized.
This comment has been minimized.
|
AFAICT you don't need to check on decrement, assuming you don't allow for compressed storage. After all, you can't run 2^32-1 destructors without 2^32-1 objects, which is infeasible. |
This comment has been minimized.
This comment has been minimized.
On unix, it's not a direct problem with the underlying API:
However, it is a problem with how we use it at the moment: #[inline]
pub unsafe fn read(&self) {
let r = ffi::pthread_rwlock_rdlock(self.inner.get());
debug_assert_eq!(r, 0);
}In particular, creating too many readers will only be detected and "handled" (panic) in debug builds. (cc @alexcrichton) I can't find any info about this for the windows APIs.
|
This comment has been minimized.
This comment has been minimized.
const WRITING: BorrowFlag = !0;Doesn't this means that if you ever get to the stage where you will overflow, you'll just trigger an "already mutably borrowed" error, no matter how you try to borrow? I modified the example (because I'm on 64 bit) and ran it (it was optimised out and it ran instantly, whoop): use std::cell::RefCell;
fn main() {
let overflower = RefCell::new(());
loop {
std::mem::forget(overflower.borrow());
}
}Output:
I guess that the error message is technically wrong but I think it's safe at least? |
This comment has been minimized.
This comment has been minimized.
|
@whataloadofwhat I can agree with that. Alternatively you can hit a |
This comment has been minimized.
This comment has been minimized.
On 32-bit upon reaching exactly 0x10000000 readers, attempts to lock it using the try version will return a failure, while the non-try version will simply deadlock. |
This comment has been minimized.
This comment has been minimized.
@Stebalien noted the possibility of a wider-than-address-space collection on the internals discussion about overflows in |
steveklabnik
added
the
A-libs
label
May 29, 2015
This comment has been minimized.
This comment has been minimized.
|
Was this fixed by #33960? |
arielb1
added
I-nominated
T-libs
I-unsound 💥
labels
Oct 14, 2016
This comment has been minimized.
This comment has been minimized.
|
Indeed fixed! |
Veedrac commentedMay 27, 2015
I don't have a 32-bit computer to test on, but I suspect that this will overflow
RefCell's counter on 32 bit builds:This can allow shared mutable pointers. I imagine similar problems hold for
Rcand co. and I imagine the problem also happens on 64 bit builds if you have it running for a few hundred years.This is what made me think of the problem:
But this isn't true if memory can be reclaimed without the destructors running (I think).
To fix it you just need to use saturating addition since only leaks can allow this to happen, and once you've leaked in this way you can't ever hope to run all the destructors anyway. (Actually, this isn't strictly true if you allow for compressed storage.)