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 up#[ffi_returns_twice] #2633
Conversation
This was referenced Feb 9, 2019
gnzlbg
force-pushed the
gnzlbg:returns_twice
branch
5 times, most recently
from
d6acad5
to
8088b92
Feb 9, 2019
gnzlbg
force-pushed the
gnzlbg:returns_twice
branch
from
8088b92
to
edb3a68
Feb 9, 2019
This comment has been minimized.
This comment has been minimized.
|
My initial thought is that I’m not sure from the RFC what the soundness and safety implications are, e.g.:
|
This comment has been minimized.
This comment has been minimized.
This attribute, as proposed in this RFC and as implemented in the PR, can only be applied to
C FFI is already unsound.
This RFC does not extend Rust with the ability to write bare functions that return multiple times. Stable Rust already allows you to just add an This RFC doesn't allow you to write your own in Rust nor tells you what these |
This comment has been minimized.
This comment has been minimized.
|
The RFC only mentions that it can be added to extern functions, but it does not explicitly prohibit use anywhere else (in fact, it doesn’t mention what happens for other types of functions at all). Perhaps that can be clarified? |
This comment has been minimized.
This comment has been minimized.
Uh, indeed. I meant functions in an |
gnzlbg
force-pushed the
gnzlbg:returns_twice
branch
from
d1daf77
to
c33392c
Feb 9, 2019
jonas-schievink
added
T-lang
T-compiler
A-ffi
labels
Feb 10, 2019
This comment has been minimized.
This comment has been minimized.
|
I thinks that’s a big improvement, but I think it would also be good to have a statement like “Adding this attribute to any other type of item is an error”. |
Centril
added
A-attributes
A-machine
and removed
T-compiler
labels
Feb 11, 2019
This comment has been minimized.
This comment has been minimized.
I find it confusing that the RFC always talks about returning multiple times but the attribute is called "twice". |
This comment has been minimized.
This comment has been minimized.
I do so too. This attribute is called The only people that will need this attribute is those reading C code on one side, and writing the Rust FFI wrapper on the other. So keeping the name the same, even if its unfortunate, makes the lives of the only users that this attribute will have easier. EDIT: the docs do say that it returns multiple times do, maybe it is worth it to call out why it is called |
This comment has been minimized.
This comment has been minimized.
|
Since you have a couple of these (I don't know if it's better, but if they interact with each other -- like IIRC you mentioned |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
|
cc @RalfJung |
This comment has been minimized.
This comment has been minimized.
|
Basically all I ask is that you make sure this
is known to everyone using
|
RalfJung
reviewed
Feb 14, 2019
| undefined behavior of the type "use-after-move". | ||
|
|
||
| In the presence of types that implement `Drop`, usage of APIs that return | ||
| multiple times requires extreme care to avoid deallocating memory without |
This comment has been minimized.
This comment has been minimized.
RalfJung
Feb 14, 2019
Member
Might be worth saying "deallocating pinned memory" here. At least to my knowledge that is the only case where we really care in terms of type system guarantees.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
RalfJung
Feb 18, 2019
Member
It is. So what?
Unsound thread spawning and Rc are also both just normal Rust libraries, and yet having one makes the other unsound. The same goes for Pin and functions that let you deallocate memory without running drop.
This comment has been minimized.
This comment has been minimized.
|
@eddyb In GCC at least, it's described as:
|
This comment has been minimized.
This comment has been minimized.
|
Then the implementation is misleadingly incomplete, since we should probably have the frontend diagnostics gcc (and presumably clang) have, regarding this, and possibly more. The "dead registers" part can be emulated with the right |
This comment has been minimized.
This comment has been minimized.
comex
commented
Feb 16, 2019
|
@eddyb I tracked that down in an earlier thread: In particular, LLVM (and thus Clang) actually does not do the dead-registers thing; the effects are more subtle. |
This comment has been minimized.
This comment has been minimized.
|
Thanks, that's pretty comprehensive. Wouldn't you need all those effects even if you had a function which, after storing enough state, never returned the first time, but rather switched to some other execution (with a different stack pointer), to come back later and "returned" via If not, why? It's still a bit unclear to me why LLVM goes to such lengths (is it working around platform bugs/limitations?). If yes, then maybe this could be made more general than "returns twice", and serve more purposes. |
This comment has been minimized.
This comment has been minimized.
comex
commented
Feb 16, 2019
Mostly no, one yes. No:
Yes:
|
This comment has been minimized.
This comment has been minimized.
comex
commented
Feb 16, 2019
Lua provides a function |
This comment has been minimized.
This comment has been minimized.
|
@comex So all the pessimisations are all about reloading a saved state knowing it couldn't have been invalidated by anything "downstack" of the call that saved said state? Which would mean "returns twice" is really "can return more than once", right? Other than for Couldn't a hypothetical And |
This comment has been minimized.
This comment has been minimized.
jeff-davis
commented
Feb 17, 2019
|
For my use case -- catching |
This comment has been minimized.
This comment has been minimized.
Correct (see the RFC).
I haven't tried but I believe you could implement similar APIs on top of |
This comment has been minimized.
This comment has been minimized.
|
@gnzlbg Disallowing the closure having a You'd need "no unwind cleanup in any code reachable from here" which is just as hard as reentrance restrictions (you can make a safe |
This comment has been minimized.
This comment has been minimized.
Yeah, I don't know if writing a There are also a whole lot of things that can trigger undefined behavior while performing a longjmp and that one has to keep in mind: not performing volatile reads / writes to memory that's modified between the setjmp and the longjmp (across multiple functions, e.g., if these functions get inlined), calling longjmp from a different thread (e.g. spawning a thread down the stack and calling longjmp there, or creating a task and sending it to an executor and trying to do longjmp from there), you need to be aware of signals, etc. One could experiment with creating APIs that improve the amount of care required for using these correctly, but for any experiment to be useful, you need to be able to use this at all. |
gnzlbg
added some commits
Feb 18, 2019
This comment has been minimized.
This comment has been minimized.
|
Yeah I was only interested in mitigating the "returns multiple times" and "can't I wasn't thinking about destructors at all. |
Centril
added a commit
to Centril/rust
that referenced
this pull request
Feb 23, 2019
bors
added a commit
to rust-lang/rust
that referenced
this pull request
Feb 24, 2019
This comment has been minimized.
This comment has been minimized.
|
If it was followed by support in the borrow checker, it would add extra baggage to an already very complex and critical component of the language. Extra complexity in the borrow checker for such niche feature is IMHO not acceptable. OTOH without support in the borrow checker, these functions are inherently dangerous to use. It's questionable why to even try to use them in Rust when all Rust adds is more footguns. Calling an intermediate C function to access these two unusual functions seems perfectly fine, and it even makes the code safer and more robust, since in the context of C functions returning twice is easier to reason about. For emulating exceptions (such as aforementioned Postgresql, as well as libjpeg and libpng), |
This comment has been minimized.
This comment has been minimized.
I'd guess its a good thing nobody is proposing that.
So is all unsafe code that we can't prove correct. |
This comment has been minimized.
This comment has been minimized.
|
Note that
This RFC does not propose adding |
This comment has been minimized.
This comment has been minimized.
Actually Since another thread is using its stack, the original thread is suspended until the vfork child has either exited or called Incidentally this is also why, like with |
This comment has been minimized.
This comment has been minimized.
|
Also, note that even |
This comment has been minimized.
This comment has been minimized.
jeff-davis
commented
Mar 1, 2019
|
@kornelski I don't understand the point about catching a postgresql exception using |
This comment has been minimized.
This comment has been minimized.
|
@jeff-davis No, never! You can't mix the two, and I would never expect them to co-operate in any way. But you can nicely replace jumping altogether. In case of libjpeg you set your error callback to |
This comment has been minimized.
This comment has been minimized.
jeff-davis
commented
Mar 2, 2019
|
@kornelski OK. My use case is working with postgres, and its error reporting / exception facility is based on So I would really like some form of |
This comment has been minimized.
This comment has been minimized.
eaglgenes101
commented
Mar 12, 2019
|
I was the one that personally suggested augmenting the borrow checker to account for multiple returns (to support library implementations of continuation mechanisms). I still have getting that through as a long-term goal, but if making it initially ffi-only and without borrow checker additions is the plan, well then. |
This comment has been minimized.
This comment has been minimized.
|
@kornelski Do you mean with some Otherwise unwinding is UB. |
This comment has been minimized.
This comment has been minimized.
|
@eddyb Yes, that's what I mean. I realize it's not fully baked in Rust yet. |
This comment has been minimized.
This comment has been minimized.
jeff-davis
commented
Apr 4, 2019
|
I see that this is merged and available in nightly (behind a feature gate). What is the path toward stabilization? Is more input/discussion needed, or just bake time? If it helps, this addresses my use case. |
This comment has been minimized.
This comment has been minimized.
|
This RFC specifies what the attribute does, and there are some issues that have been raised about the RFC but have not been resolved yet, so that would need to be done. After that, the corresponding teams would need to vote on whether this should be merged or not (just normal process). This RFC leaves the syntax as an unresolved question, so even if this RFC is merged, stabilization would be blocked on the syntax issue being resolved. We will probably need a different RFC proposing a more holistic approach to FFI attributes in general. There is an issue open about that: #2637 . |
gnzlbg commentedFeb 9, 2019
Rendered.
Implementation PR.
Closes #2625.