-
Notifications
You must be signed in to change notification settings - Fork 13.6k
Closed
Labels
A-destructorsArea: Destructors (`Drop`, …)Area: Destructors (`Drop`, …)A-docsArea: Documentation for any part of the project, including the compiler, standard library, and toolsArea: Documentation for any part of the project, including the compiler, standard library, and toolsC-enhancementCategory: An issue proposing an enhancement or a PR with one.Category: An issue proposing an enhancement or a PR with one.I-needs-decisionIssue: In need of a decision.Issue: In need of a decision.T-langRelevant to the language teamRelevant to the language team
Description
It was decided in, I think, #14875, that Drop::drop
can panic, and if this happens, the value must be leaked (at least in a generic context), that is, it cannot be re-dropped again and doing that could invoke UB (that's at least what generic unsafe code needs to assume).
This does not appear to be documented anywhere. These semantics make the following snippet have undefined behavior due to double-drops (playground uses T = Vec<HasDrop>
):
let mut a: T;
let a_raw = &mut a as *mut T;
match std::panic::catch_unwind(|| {
// Drop `a` in place:
unsafe { std::ptr::drop_in_place(a_raw) };
}) {
// For exposition only, if the value isn't leaked,
// it will be re-dropped, but one could also try to
// explicitly re-drop on drop failure.
// UB: this will double-drop some previously dropped fields of a
Err(_) => std::mem::drop(a),
// If dropping succeeds, leak a
Ok(()) => std::mem::forget(a),
}
To avoid UB, that snippet must be changed to unconditionally leak the value independently of whether drop_in_place
succeeded or failed:
let mut a: T;
let a_raw = &mut *a as *mut T;
std::panic::catch_unwind(|| {
// Drop `a` in place:
unsafe { std::ptr::drop_in_place(a_raw) };
});
// Always leak `a`: if dropping failed, some elements will be leaked,
// but there is no way to properly drop them and trying to re-drop
// a could invoke UB
std::mem::forget(a);
cc @Centril - this might be a T-lang issue, I don't know the best way to word this, and I can't find any RFC designing this part of the language.
Metadata
Metadata
Assignees
Labels
A-destructorsArea: Destructors (`Drop`, …)Area: Destructors (`Drop`, …)A-docsArea: Documentation for any part of the project, including the compiler, standard library, and toolsArea: Documentation for any part of the project, including the compiler, standard library, and toolsC-enhancementCategory: An issue proposing an enhancement or a PR with one.Category: An issue proposing an enhancement or a PR with one.I-needs-decisionIssue: In need of a decision.Issue: In need of a decision.T-langRelevant to the language teamRelevant to the language team
Type
Projects
Milestone
Relationships
Development
Select code repository
Activity
tesuji commentedon May 7, 2019
@rustbot modify labels: T-lang T-doc
Centril commentedon May 7, 2019
cc @rust-lang/wg-unsafe-code-guidelines @rust-lang/lang
frewsxcv commentedon May 8, 2019
Previous issue: #50765
And also: rust-lang/reference#348
tmandry commentedon May 16, 2019
Related: #60840 (comment)
hkBst commentedon Mar 14, 2025
https://doc.rust-lang.org/nightly/std/ops/trait.Drop.html#tymethod.drop currently includes
"""
Note that even if this panics, the value is considered to be dropped; you must not cause drop to be called again. This is normally automatically handled by the compiler, but when using unsafe code, can sometimes occur unintentionally, particularly when using ptr::drop_in_place.
"""
This was added in ##67559
So I think this can be closed.
RalfJung commentedon Mar 16, 2025
Agreed, thanks for gathering the references.
There are some discussions for further changes here, but those are already tracked elsewhere:
catch_unwind
when catching panic-on-drop types #86027