-
Notifications
You must be signed in to change notification settings - Fork 140
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Panics on drop will cause double drops. #3
Comments
Test cases (abusing rust's panic on drop -> abort). #[test]
#[should_panic]
fn test_drop_panic() {
struct DropPanic;
impl Drop for DropPanic {
fn drop(&mut self) {
panic!("drop");
}
}
let mut array = ArrayVec::<[DropPanic; 1]>::new();
array.push(DropPanic);
}
#[test]
#[should_panic]
fn test_drop_panic_into_iter() {
struct DropPanic;
impl Drop for DropPanic {
fn drop(&mut self) {
panic!("drop");
}
}
let mut array = ArrayVec::<[DropPanic; 1]>::new();
array.push(DropPanic);
array.into_iter();
} |
Thanks! I guess this won't be easy.. |
We need to make sure the NoDrop enum's discriminant is set to Dropped, even if we panic during drop of one of the elements. Bug reported by @Stebalien Fixes #3
For the lols, please read #5. Hey you said you would leave it for me to fix! But I do think you have the sane version, and I the insane.. |
ArrayVec::drop was not panic safe — if there would be a panic during an element's drop, the discriminant would never be set to Dropped, and the array elements would potentially double drop. Fix this by going back to the old NoDrop composition. The NoDrop struct thas its own Drop impl, that will trigger too on panic during an element's drop. This serves to make ArrayVec::drop panic safe. Also tweak IntoIter::drop to make it panic safe: set inner ArrayVec's length before dropping any elements. Thank you to @Stebalien for reporting this bug and providing the excellent testcases in this commit. Using NoDrop expands ArrayVec to have two drop flags again, but this is a temporary tradeoff, drop flags will eventually go away. Fixes #3
Fixed in version 0.3.10. Use (unstable) feature flag nodrop/no_drop_flag to recover size. (However, it's not completely equivalent in terms of overhead, even if the size is the same.) |
Great, now it's fixed in smallvec too. |
Add -Z panic-in-drop={unwind,abort} command-line option This PR changes `Drop` to abort if an unwinding panic attempts to escape it, making the process abort instead. This has several benefits: - The current behavior when unwinding out of `Drop` is very unintuitive and easy to miss: unwinding continues, but the remaining drops in scope are simply leaked. - A lot of unsafe code doesn't expect drops to unwind, which can lead to unsoundness: - servo/rust-smallvec#14 - bluss/arrayvec#3 - There is a code size and compilation time cost to this: LLVM needs to generate extra landing pads out of all calls in a drop implementation. This can compound when functions are inlined since unwinding will then continue on to process drops in the callee, which can itself unwind, etc. - Initial measurements show a 3% size reduction and up to 10% compilation time reduction on some crates (`syn`). One thing to note about `-Z panic-in-drop=abort` is that *all* crates must be built with this option for it to be sound since it makes the compiler assume that dropping `Box<dyn Any>` will never unwind. cc rust-lang/lang-team#97
IntoIter and ArrayVec need to be poisoned to prevent dropping before being drained; otherwise, if one of the elements panics on drop, it will be dropped twice. I've worked on a couple of solutions but they all have design tradeoffs so I figured I'd just let you fix it.
Drain doesn't have this issue because the ArrayVec's length is set to 0 when the Drain is initialized.
The text was updated successfully, but these errors were encountered: