Repository navigation
Default behavior of unwinding in FFI functions #58794
Description
Activity
- addedT-langRelevant to the language teamRelevant to the language teamC-tracking-issueCategory: An issue tracking the progress of sth. like the implementation of an RFCCategory: An issue tracking the progress of sth. like the implementation of an RFC
on Feb 28, 2019 It would be helpful for the discussion if someone knowledgeable could write a summary covering the following:
- What are the issues with allowing unwinding through foreign languages on major platforms? What is the interaction with C++ exceptions? (Saying it's "UB" doesn't cut it)
- What is the interaction between setjmp/longjmp and unwinding (in general, and on major platforms)?
- Are there any concrete plans for writing a custom unwinder/"tweaking the unwinder"? Has anyone tried this/is anyone working on this? (The answer to this question may be used to determine how Rust restricts itself by locking into the standard unwinder on major platforms.)
When I say major platforms, I mean GNU libunwind, Windows SEH, possibly others.
Is it possible to have different default behavior depending on which unwinder you're using? Say, unwind normally on major platforms, abort on others?
- What are the issues with allowing unwinding through foreign languages on major platforms? What is the interaction with C++ exceptions? (Saying it's "UB" doesn't cut it)
In another thread, @alexcrichton wrote:
From a technical perspective this is pretty feasible, but from a stabilization perspective is historically something we've never wanted to provide. We want the technical freedom to tweak unwinding as we see fit, which means it's not guaranteed to match what C++ does across every single platform.
As for the current implementation, my understanding is: on Unix it works; on Windows it mostly works, with some issues that could be solved. See my comment in that thread for more details.
- What is the interaction between setjmp/longjmp and unwinding (in general, and on major platforms)?
On Unix, longjmp just resets the stack pointer and ignores unwinding.
On Windows, longjmp triggers SEH unwinding and so will run Rust destructors, AFAIK. *
* (I said in other threads that it didn't, because I misread the description of this PR and thought that it changed things so destructors wouldn't run when unwinding via longjmp; in reality, it only did that to the abort-on-unwind handler itself.)
On Windows, longjmp triggers SEH unwinding and so will run Rust destructors
As far as the last part of that is concerned, that is an implementation-specific and unspecified behaviour.
The current behavior on stable amounts to a soundness hole. For example, based on #52652 (comment), we can write (playground):
extern "C" fn bad() { panic!() } fn main() { bad() }
The behavior of this program is undefined on stable because we attach the
nounwindLLVM attribute tobad.Soundness is non-negotiable and as such we landed #55982 to close this soundness hole. However, since there was no explicit confirmation of this step by the language team the change was reverted on 1.33 pending confirmation. The change is still seen in beta and nightly compilers.
Based on notes by @alexcrichton in #52652 (comment), #55982 (comment), #55982 (comment), and #55982 (comment), I propose that we go ahead with and confirm the change in #55982.
@rfcbot merge
Reacted by anderejd, eternaleye, Aaron Hill and Daira-Emma HopwoodTeam member @Centril has proposed to merge this. The next step is review by the rest of the tagged team members:
Concerns:
blocked-on-rfc-2699resolved by Default behavior of unwinding in FFI functions #58794 (comment)- blocked-on-rfc-2753 (Default behavior of unwinding in FFI functions #58794 (comment))
- need-documented-replacement (Default behavior of unwinding in FFI functions #58794 (comment))
Once a majority of reviewers approve (and at most 2 approvals are outstanding), this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up!
See this document for info about what commands tagged team members can give me.
- addedproposed-final-comment-periodProposed to merge/close by relevant subteam, see T-<team> label. Will enter FCP once signed off.Proposed to merge/close by relevant subteam, see T-<team> label. Will enter FCP once signed off.disposition-mergeThis issue / PR is in PFCP or FCP with a disposition to merge it.This issue / PR is in PFCP or FCP with a disposition to merge it.
on Mar 10, 2019 This change was tried twice, and twice it was reverted because important parts of the ecosystem broke. Do we really want to try merge it again without any changes?
The discussion on this topic is pretty fragmented, the internals thread mentioned in the top post has been quite active as well. I'm still waiting for the summary I requested #58794 (comment). I thought the scope of this issue is much bigger than what @Centril just mentioned. If you only care about the soundness issue at the IR level, another way to fix it is to never emit the nounwind attribute.
Reacted by Vadim PetrochenkovThis change was tried twice, and twice it was reverted because important parts of the ecosystem broke.
This is untrue. The second time it was reverted it was reverted only because of the lack of a completed T-Lang FCP (which we are doing now).
Reacted by Daira-Emma Hopwood131 remaining items
@joshtriplett I don't want to create a divide where there is none, but it seems to me that @gnzlbg is advocating to just stop emitting
nounwindto LLVM altogether while we wait for a solution. I don't see them expressing an opinion on stabilizing (or removing) theunwind(allowed)attribute.Reacted by Kyle J Strand and gnzlbg@BatmanAoD I would like to see your RFC continue, to develop a more precise specification of panic behavior. But I'd also like to see
#[unwind(allowed)]stabilized more-or-less as-is, as soon as reasonably possible.@jethrogb If we can't trivially get
#[unwind(allowed)]stabilized, then I'm all for fixing the problem that way, but if we can get#[unwind(allowed)]stabilized quickly then let's do that.Reacted by Kyle J Strand@joshtriplett Here is the tracking issue for stabilizing
#[unwind(allowed)]: #58760- added a commit that references this issue
on Aug 25, 2019 - added a commit that references this issue
on Aug 26, 2019 For those watching, @joshtriplett just proposed a simple
#[unwind]specification.Reacted by Kyle J Strand@rfcbot resolved blocked-on-rfc-2699
@rfcbot concern blocked-on-rfc-2753Summarizing much further discussion: RFC 2699 is a much more general "how do we handle cross-language panics/unwinds/etc", while RFC 2753 is a much simpler proposal to just provide an
#[unwind]attribute to disablenounwindand fix the UB.Reacted by Sander Maijers- added a commit that references this issue
on Sep 13, 2019 @rfcbot fcp cancel
So a lot has happened since this FCP was created. In RFC rust-lang/rfcs#2797, we created the ffi-unwind project group, for one thing. One of the first things we've been doing is debating this exact topic in some depth. Therefore, I'm going to cancel this FCP and close this issue -- we expect to try and resolve this issue very soon with a firmer decision about the direction we're going, and we'll re-evaluate in light of that.
@nikomatsakis proposal cancelled.
- removedproposed-final-comment-periodProposed to merge/close by relevant subteam, see T-<team> label. Will enter FCP once signed off.Proposed to merge/close by relevant subteam, see T-<team> label. Will enter FCP once signed off.disposition-mergeThis issue / PR is in PFCP or FCP with a disposition to merge it.This issue / PR is in PFCP or FCP with a disposition to merge it.
on Nov 22, 2019 If you'd like to participate in the group, btw, most of the discussion has been taking place in Zulip in the
#wg-ffi-unwindstream.
This is the tracking issue for the behavior of unwinding through FFI functions.
There are two choices here: we can abort if unwinding occurs through an
extern "C"boundary. We abort on beta 1.34 and nightly 1.35, but will permit unwinding in stable 1.33.We previously attempted this change in 1.24 and reverted in 1.24.1. We attempted to do so again in 1.33, but reverted once again pending lang team discussion on the topic.
There has been discussion on this topic in #52652, #58760, and #55982.
The stable behavior of permitting unwinding is UB, and can be triggered in safe code (#52652 (comment)). Notably,
mozjpegdepends on this behavior and seems to have no good stable alternatives; there's been some discussion on internals.There is an RFC discussing this: rust-lang/rfcs#2699.