Join GitHub today
GitHub is home to over 31 million developers working together to host and review code, manage projects, and build software together.
Sign upprevent unwinding past FFI boundaries in code generation #18510
Comments
thestinger
added
I-wrong
A-codegen
labels
Nov 1, 2014
thestinger
added
the
I-nominated
label
Nov 1, 2014
This comment has been minimized.
This comment has been minimized.
|
Assigning P-high, not 1.0. |
pnkfelix
added
P-medium
and removed
I-nominated
labels
Nov 6, 2014
Aatch
referenced this issue
Jan 15, 2015
Closed
Mark extern functions as nounwind + other unwinding-based improvements #21186
This comment has been minimized.
This comment has been minimized.
|
Triage: I'm not aware of a code change here, I believe that we are expecting people to handle this themselves with /cc @rust-lang/libs @rust-lang/lang is that the only solution we are pursing here, or do we plan on doing it automatically eventually? |
This comment has been minimized.
This comment has been minimized.
|
@steveklabnik IIRC, there's still work to do to ensure that you correctly get an abort if you don't recover from the panic before hitting the boundary. I believe that's what this issue is about. |
This comment has been minimized.
This comment has been minimized.
|
cc @ranma42 |
brson
added
P-low
I-unsound 💥
T-compiler
and removed
P-medium
labels
Aug 25, 2016
This comment has been minimized.
This comment has been minimized.
coder543
commented
Jul 10, 2017
•
|
Has there been any work done on this? Automatically inserting catch_unwind statements at FFI boundaries that automatically abort on uncaught panics seems like a straightforward way to close this soundness hole. I see where @brson silently adjusted the tags, so maybe the core team reviewed it back in August. |
This comment has been minimized.
This comment has been minimized.
|
UPDATE: This comment appears to have been a bit confused! See revised instructions below. No work has been done on this to my knowledge, but I am in favor of the solution you proposed @coder543, and would be happy to work with you on implementing it. If nothing else, it would help us gain experience with overhead etc. I think that the strategy we would use is to modify the code that generates MIR (our mid-level intermediate IR) for calls, which is found in this file here. You can see that it generates the code to execute upon unwind right here, on this line -- currently, this is always cleanup code. We could modify it to inspect the type of the value being invoked (and, in particular, its ABI) and generate alternate unwind code that aborts (I'm not sure the best way to encode an abort right now though). The function being called is stored in the The main question then is how to generate MIR that aborts. Right now I think we have no way to encode an abort into the IR. We could probably add an ABORT terminator (i.e., a new variant of the MIR data structure So, if you were going to implement this, I think we would do the following steps:
That might be two PRs, or maybe one. To get started, one might also skip the first step, and just experiment with having the compiler print out a match when it finds a C ABI function, and then worry about how to handle it. |
nikomatsakis
added
the
E-mentor
label
Jul 17, 2017
This comment has been minimized.
This comment has been minimized.
coder543
commented
Jul 17, 2017
|
I'm happy to give it a shot!
I mean, isn't using this in a function going to generate some MIR that leads to an abort? Would it be possible to just generate either that, or something equivalent to the MIR for ::sys::abort_internal?
That seems like a good way to start this. I'll go ahead and get things set up here to start doing compiler dev. The compiler is doing its inital build now under Ubuntu 17.04. |
This comment has been minimized.
This comment has been minimized.
coder543
commented
Jul 18, 2017
•
|
I have things set up where I can print things to stderr from the relevant block of code, recompile through stage 1 for fast rebuilds, and then use the generated compiler to compile a small Rust source file, which causes those debug print statements to be generated. So, everything is configured. Now, to "just" figure out how to print out a match when encountering a C ABI function. I'm done for tonight, but I hope to pick it up again tomorrow evening. |
This comment has been minimized.
This comment has been minimized.
coder543
commented
Jul 18, 2017
•
|
I actually ended up staying awake for a little longer, and I now have it only debug print a message when it encounters a function call to a C ABI function. I'm not sure |
This comment has been minimized.
This comment has been minimized.
coder543
commented
Jul 19, 2017
|
@nikomatsakis I think at this point it's safe to say I'm going to need help figuring out where to go from here. |
Mark-Simulacrum
added
C-feature-request
C-bug
and removed
C-enhancement
C-feature-request
I-wrong
labels
Jul 22, 2017
This comment has been minimized.
This comment has been minimized.
|
@coder543 Are you still interested in working on this? If not I might try to during the "impl days" in RustFest Zurich. @nikomatsakis It sounds like this is blocked on a mentor providing some more help ;) |
This comment has been minimized.
This comment has been minimized.
|
I still doesn't understand whether this issue is supposed to apply to Rust code calling an |
This comment has been minimized.
This comment has been minimized.
|
The current situation is that foreign functions are marked as |
This comment has been minimized.
This comment has been minimized.
|
I assumed the latter: Rust unwinding into some foreign stack frame is the case where we have some control? |
This comment has been minimized.
This comment has been minimized.
coder543
commented
Sep 19, 2017
|
@SimonSapin feel free to take over! |
This comment has been minimized.
This comment has been minimized.
|
@coder543 hey, sorry I dropped the ball on those notifications! Missed them somehow. Still digging out of a months-long hole. Also, re-reading my mentoring instructions, I think I was confused! That is, I also believe that the goal is to catch unwinds in an That said, it's still true that we need an abort terminator, but the job is substantially easier I think. We just need to find when we are generating MIR for @arielb1 does that sounds reasonable to you? |
This comment has been minimized.
This comment has been minimized.
coder543
commented
Sep 22, 2017
|
@nikomatsakis Hey, it's alright. I would have loved to help on this issue, but I'll look for other |
This comment has been minimized.
This comment has been minimized.
|
Okay, since I've been complaining about this bug I think maybe I should make an attempt to fix it. :-) But it's my first time this far into the compiler. I started off with this advice:
I could not find any specific "final unwind block" that's already generated. And in the case where the C function merely calls another (Rust) function, why should there be one? edit: The function changed is librustc_mir/build/mod.rs:construct_fn.
Does this seem reasonable, or am I just completely far off so that I better leave it to someone more knowledgeable in order not to consume your time? (Ping @nikomatsakis or someone else who would like to provide some mentoring here) |
This comment has been minimized.
This comment has been minimized.
|
@diwic you're in the right general direction -- but I think what I had in mind was modifying the terminator that we create on this particular line. This is lazilly constructed when there is a need to generate unwinding code. (Oh, and plausibly yes we could do the same for PS feel free to reach out on gitter as well. |
This comment has been minimized.
This comment has been minimized.
|
It's a lot to take in if you have not worked on the compiler's internals before. So I'm working on it, but not very fast... @nikomatsakis Assume the following code:
Here's the MIR output for
there is no resume cleanup block that we can modify. So instead we need to add a new one, I believe?
This is what I want to do:
...because that's when we tell LLVM our function is nounwind. But probably I picked the wrong id, because it returns false regardless of abi. |
This comment has been minimized.
This comment has been minimized.
iainnicol
commented
Oct 2, 2017
|
Would it be possible to opt out of the abort generation? Perhaps by tagging the function with the existing #[unwind] attribute? My use case is that I would like to be able to catch Rust panics from the C/C++ side. This is for writing a standard library for a toy language. I realise such unwinding is undefined and hence there are no guarantees. But it would still be useful, at my own risk. |
rkruppe
referenced this issue
Oct 4, 2017
Open
mutable noalias: re-enable permanently, only for panic=abort, or stabilize flag? #45029
diwic
added a commit
to diwic/rust
that referenced
this issue
Oct 7, 2017
This comment has been minimized.
This comment has been minimized.
I have two concerns about this approach: 1) does it really work in practice, and if so what kind of exception is a Rust exception in C++ and 2) why can't you use |
This comment has been minimized.
This comment has been minimized.
|
@nikomatsakis or anyone who would like to provide mentoring/review/feedback: So I made some progress today! (Yay!) As can be seen in diwic@729092c It's probably not ready for PR yet, could use some mentoring / feedback:
|
This comment has been minimized.
This comment has been minimized.
Yes! Tests should definitely be added. One way to do this is to write a
Can you say a bit more, I'm not sure what that means?
OK, I'll double-check when you open a PR.
It is experimental and does not happen by default. You can enable it with In general, it'd be great if you wanted to open a PR and we can discuss in more depth there! Feel free to tag it with |
This comment has been minimized.
This comment has been minimized.
|
Second attempt here: #46833 |
diwic
added a commit
to diwic/rust
that referenced
this issue
Dec 21, 2017
bors
closed this
in
4910ed2
Dec 24, 2017
This comment has been minimized.
This comment has been minimized.
|
Thank you so much for pushing on this old bug @diwic! |
This comment has been minimized.
This comment has been minimized.
JFTR, as implemented, tagging the function with the #[unwind] attribute does opt out of the abort generation. |
steveklabnik
reopened this
Mar 2, 2018
This comment has been minimized.
This comment has been minimized.
|
re-opening as 1.24.1 removed this behavior, even though it's expected to come back soon. |
This comment has been minimized.
This comment has been minimized.
|
|
This comment has been minimized.
This comment has been minimized.
|
Closing this in favor of #52652 (which is more recent and active). |
Mark-Simulacrum
closed this
Jul 29, 2018
This comment has been minimized.
This comment has been minimized.
|
Oops, sorry I didn’t find this when opening #52652 ! |
thestinger commentedNov 1, 2014
•
edited by nikomatsakis
It's undefined to unwind past an FFI boundary such as a
pub extern "C" fn. Code generation should automatically insert a landing pad doing an abort. This will eliminate the class of memory safety errors resulting from unwinding into C from Rust. LLVM will be able to optimize it out if it is being caught and handled explicitly, such as to translate into an error code for C.EDIT: Mentoring instructions can be found here.