-
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
Default behavior of unwinding in FFI functions #58794
Comments
See rust-lang#58794 for context.
It would be helpful for the discussion if someone knowledgeable could write a summary covering the following:
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? |
In another thread, @alexcrichton wrote:
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.
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.) |
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 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 |
Team member @Centril has proposed to merge this. The next step is review by the rest of the tagged team members: Concerns:
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. |
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. |
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). |
I don't think so. If no one in the community would've complained about the change, I don't think this would've been reverted a day before the stable release even though no lang team discussion had happened yet. That might've been used as justification to actually do the revert, but it's certainly not the only reason. |
@jethrogb It most definitely was the only reason; the release team cannot undo language team decisions and had there been one we would not have reverted. |
@Centril I'm saying that if there hadn't been any backlash no one would've even proposed to undo the change. |
@jethrogb Yes, there was backlash, but that was irrelevant to the acceptance or non-acceptance of the undo-PR itself. The sole reason for accepting the undo-PR was the lack of a completed T-Lang FCP. |
I don't have enough information to argue about procedural details and people's rationale for r+'ing this or that PR, and I wouldn't be very interested in doing so anyway. I just want to say that in the light of the the ongoing discussions and continued lack of consensus on how to address the legitimate needs of some projects to unwind through FFI, it seems premature to me to take this step now, just as it was premature the last times. Soundness is ultimately not negotiable, but there can absolutely be bad times and ways to roll out soundness fixes. |
It was suggested to me in a private conversation that this might lead to performance loss. I'd like to see some numbers on that. Because things “work” most of the time right now, it seems to me that LLVM currently generates code that would be similar to the code it would generate without nounwind. I wholeheartedly agree with @rkruppe. I feel like not emitting nounwind is a good alternative to fix the unsoundness now (although not solving UB in general), while keeping users happy, and it gives us time to search for a real solution. For this real solution, I'd like to see an RFC-style discussion with a solid motivation and discussion of alternatives. |
As long as the soundness hole is closed one way or the other (aborting, not emitting However, I think we should separate discussion about new mechanisms like |
I don't feel it is helpful to draw such an antagonistic picture. There literally is no way to do FFI unwinding safely in Rust currently, and some people got frustrated enough by that that they went with something that "happens to work". I have hacked around limitations in ugly ways often enough that I can totally sympathize. Sure, they should instead have written an RFC to provide a defined way to do what they needed to do, but that's a lot of work and not everyone is up for that kind of contribution. The |
@Centril It is indeed a possible outcome that the relevant teams ultimately decide "damn those programs and use cases, we won't provide a way to unwind through FFI". However, that would be a decision with severe downsides (more social ones than technical ones) which I don't think should be taken lightly, and IMO not at this very moment but rather after the other options have been explored and rejected -- as @RalfJung said, the trajectory of While it's all good and well to say "this is UB, we've always said so, and programs with UB are completely invalid", the Rust project really made its bed itself here by not acting on the subject for years and in particular not providing an alternative way to address the very reasonable needs that cause users to write programs with this UB. We now have the situation that people trying to do certain (fairly reasonable!) things with Rust not only have no way to achieve it without writing programs that have UB, they do not even have an alternative in sight that they could switch to when those programs break. Rust is well within its rights to break those programs, and I am definitely not arguing that the de facto behavior of today should be ad-hoc blessed as defined behavior, but it will cause users serious problems to not provide some alternative way to do what they need to do. We should not cause users such problems if we can reasonably avoid it, even if it means delaying a soundness fix. For comparison, some type system soundness bugs get a long grace period of time where the compiler warns instead of erroring on wrong programs to help people fix it before they get broken. Such a warning is not possible in this case (as it's about runtime behavior), but we should similarly do our best to ease the pain. Holding off pulling the trigger for another couple months (peanuts compared to how long the soundness issue has been open!) while waiting on other issues get worked out is a quite easy way to do that. |
I think there are also severe social downsides to not going ahead with this. Namely, we legitimize "There's no way to do X currently, so we'll do something that happens to work".
I first heard of the existence of
None of this suggests that "The
Yes, I'm quite unhappy about the inaction here. I think the reason for the inaction has precisely been that we didn't want to break anyone. In the future I hope that we set deadlines for and better track soundness holes and C-future-compatibility issues.
I think it is entirely reasonable that people use nightly until such time and help test the
I'm well aware of C-future-compatibility issues and but I think we let them sit around for far too long without actionable and well-triaged plans to address them. I think we are in need of schedules and deadlines. |
On a philosophical level, I disagree. It's not a question of "legitimizing". It's a fact of life that people will rely on implementation details whether they're supposed to or not, unless you actively prevent them from doing so. Ideally you do prevent them, like rustc does with On a more practical note, among the links in the original post, I think this (from here) is a key quote:
My thoughts:
Of course, this needs to go through an RFC. I don't think it needs to be a particularly "hard" RFC, at least if we're just stabilizing unwinding across C; it could be accepted quickly enough that there would be basically no benefit in changing the implementation to abort by default in the meantime. But this seems to have been rather controversial so far, so who knows... For that to happen, someone needs to write the RFC. Does anyone want to volunteer to do that? Should I? I also think it would be useful to fix and stabilize unwinding across C++, as a feature which might have an even narrower set of supported platforms, but which is not at all hard to implement on most existing platforms and could be quite useful for mixed C++-Rust codebases. But that comes later. |
Oh, one more thing (I'd edit this in, but that doesn't help people reading via email): If the unwind attribute is stabilized, rather than |
@rfcbot concern need-documented-replacement In the absence of a documented replacement for how people should handle errors in C libraries that only support handling through unwinding, closing this would break a common use case. Another way to fix the UB might be to drop the LLVM "nounwind" attribute. We could also add I'm happy to support this as a sensible default after we document exactly what we expect people to do when interacting with inflexible C libraries that expect unwind-based error handling. |
I wanted to apologize. I was called out by using the unconstructive word malice here. In that sentence, by us, I meant rustc, the tool, as in, it would be "evil" for rustc to continue emitting @joshtriplett I agree with you about just trying to remove In retrospect, we have had a mis-optimization that impacts all Rust users and a PR to fix it for over a year. During this whole time, we always had the chance to just stop emitting |
[beta] Permit unwinding through FFI by default This repeats #61569 for Rust 1.37, as #58794 is not yet resolved. cc @rust-lang/release r? @Mark-Simulacrum
@gnzlbg Thank you for taking the time to explain in more detail, and thank you for taking the time to understand the problem and past stresses involved. It sounds like we're now in agreement on the right ways forward here? Let's introduce the simplest possible mechanism to just remove Once we have that in place, we also need to decide how long after that we start aborting again on unwind of an extern function call tagged with @rust-lang/lang and @gnzlbg: Do you believe that the easiest path forward is a new RFC or some updates to RFC 2699? I'm starting to think that a new RFC might be better, and then we can leave RFC 2699 for the problem of standardizing panic/unwind ABIs. |
@joshtriplett Note that the Having recommended in my RFC that the attribute itself be dependent on the compiler's ability to verify that the |
@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 |
@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 @jethrogb If we can't trivially get |
@joshtriplett Here is the tracking issue for stabilizing |
See rust-lang#58794 for context.
Permit unwinding through FFI by default This repeats #62505 for master (Rust 1.38+), as #58794 is not yet resolved. This is a stopgap until a stable alternative is available, like [RFC 2699](rust-lang/rfcs#2699), as long as progress is being made to that end. r? @joshtriplett
For those watching, @joshtriplett just proposed a simple |
@rfcbot resolved blocked-on-rfc-2699 Summarizing 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 |
See rust-lang#58794 for context.
@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. |
If you'd like to participate in the group, btw, most of the discussion has been taking place in Zulip in the |
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,
mozjpeg
depends 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.
The text was updated successfully, but these errors were encountered: