-
Notifications
You must be signed in to change notification settings - Fork 12.9k
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
clarify interaction of pin drop guarantee and panics #71607
Conversation
(rust_highfive has picked a reviewer for you, use r? to override) |
Cc @rust-lang/lang for the pin drop guarantee |
Yep, LGTM |
Maybe this should go through T-lang FCP, not sure. |
@rust-lang/lang the question for nomination is: do you all agree with what the docs say in this PR -- that it is okay to deallocate the memory backing pinned data after calling its At least for stack pinning, this is pretty much the only possible option: when something is pinned in a stack slot, unwinding will continue if the destructor panics, and thus the memory will get deallocated. Without the semantics I am proposing, Stack pinning would have to somehow abort-on-panic-in-drop to be sound. However, I do not know how well existing unsafe code that interacts with the pin drop guarantee handles panics occurring in its drop impl. In particular this means that pinned "containers" (generic types that have pinned fields, including |
@RalfJung the only sane alternative I can think of would be to disallow panicking from destructors of pinned data entirely (ie. make it UB or an immediate abort). |
I don't think UB is a reasonable option at all, but we could consider abort, yes. That is still an option even if we adopt this now -- my proposal is future-compatible with aborting. |
ping @cramertj |
Based on some discussion in the lang team triage meeting:
|
I do not know with which intent you state this fact here. This just means that when one field's drop panics, the next field's drop needs to be called (like the native drop glue does for structs and arrays etc, and like properly exception-safe destructors should everywhere). So, this is not in contradiction with saying "if you call drop and it panics, you can free the memory". If you want to say that there is a problem here or that this means we cannot adopt the PR, then please explain, as I do not think that is the case. |
Argh, I had an in-progress comment here in ... some tab. Probably I'll find it later. I wanted to ask @RalfJung a clarifying question. It seems to me that, as you say, we already have the expectation that -- if a drop panics -- the memory might be freed anyway, so the Drop is responsible for aborting in that case. I'm not very happy about this, and I wonder if we could get away with changing it, but it's certainly true now. Given that, I'm not really sure what alternative there is to what is documented here -- it would have to be, I believe, that somehow the drop machinery will abort, right? But it's not very clear to me if there is any way for us to make the drop machinery catch the panic and abort that specifically targets pinned memory and not other memory. So my question is: Are there any proposals for such a mechanism? Zlso, I guess, does the rest of the logic in this comment sound correct to you. |
Yeah, there's not really any alternative I can think of. But I also felt like I shouldn't land a docs change like this without consulting T-lang, to at least make sure y'all are aware of the situation here. Also maybe one of you would have come up with an alternative. Maybe I was overcautious. |
Well, the main alternative I have in my mind is..maybe we can just make all drops abort on panic. I think that was definitely a mistake not to do so -- or at least, change the default (but allow an opt-out), or something like that. I imagine that some people are relying on the current behavior, though. I feel like we've had this conversation enough times I should have the "patterns" at the tip of my tongue, but I don't presently. |
But that seems orthogonal to this documentation PR =) |
@nikomatsakis I suppose you could add the abort automatically to the compiler-generated drop glue for types which don't implement |
Agreed. :D |
Here's the scenario I was concerned about. If this is possible, I think it's an argument that we need to fix this somehow rather than just documenting it: Suppose I have a pinned buffer on the stack, and some other component has a pointer to that buffer which it will use as the target of a write, and the drop for that pinned buffer (call it A) arranges with that other component to cancel the write before the memory gets freed. Now, suppose that a different drop (call it B) panics. In the course of unwinding, we free the stack memory without calling drop A, and we start to unwind the stack. We then call another drop (call it C), which uses (directly or indirectly) enough stack to overlap where that buffer used to be. Then the other component writes through the pointer, having not been cancelled. The stack is now scribbled-on and corrupted. Now drop C tries to return, using the corrupted stack, which best-case crashes and worst-case runs arbitrary code. (If the buffer being written into was arbitrary network data, this would be a remotely exploitable security hole.) With that scenario in mind: are you saying that even if one drop panics, we'll still call every other drop that doesn't directly depend on that one, so the only way we can free memory without calling its corresponding drop is if that drop call panics? That would be a little more reasonable; it still means the drop has to do a Is there any circumstance under which the above scenario could happen? (I still think we should try to find a way to transition to "panic in drop is automatically abort", but that might be a difficult transition. I wonder if any code actually relies on this behavior, though.) |
Why would it skip the destructor of
Yes. As far as I know, that's how recursive dropping should work.
Indeed the
Not without a soundness bug elsewhere, I don't think. For example, it used to be the case that Does this answer your question? |
So @RalfJung I believe the answer is that we are clear to land this PR, yes. |
I think the doc comment clarification is fine and I think there's no particular interaction between pin and drop panics, except maybe pinning highlights that a destructor which panics can be quite error-prone. Any change to the behavior of panic in drop should be made across the board and have nothing to do with whether values are pinned or not. (My understanding is that this is the consensus viewpoint.) |
@RalfJung Thank you for the detailed explanation; that fully addresses my concerns. |
@bors r+ rollup |
📌 Commit 33541d5 has been approved by |
Rollup of 6 pull requests Successful merges: - rust-lang#71607 (clarify interaction of pin drop guarantee and panics) - rust-lang#72125 (remove broken link) - rust-lang#72133 (Add target thumbv7a-uwp-windows-msvc) - rust-lang#72304 (rustc_target: Avoid an inappropriate use of `post_link_objects`) - rust-lang#72309 (Some renaming and minor refactoring for `NativeLibraryKind`) - rust-lang#72438 (Enable ARM TME (Transactional Memory Extensions)) Failed merges: r? @ghost
Cc rust-lang/unsafe-code-guidelines#232
@Diggsey would this have helped?