-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add an attribute to indicate that a function might return multiple times
- Loading branch information
Showing
1 changed file
with
106 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
- Feature Name: ffi-returns-twice | ||
- Start Date: 2019.02.08 | ||
- RFC PR: (leave this empty) | ||
- Rust Issue: (leave this empty) | ||
|
||
# Summary | ||
[summary]: #summary | ||
|
||
This RFC adds a new function attribute, `#[ffi_returns_twice]`, which indicates | ||
that an `extern` function can return multiple times. | ||
|
||
# Motivation | ||
[motivation]: #motivation | ||
|
||
Rust assumes that function calls like: | ||
|
||
```rust | ||
let x = foo(); | ||
``` | ||
|
||
return only once. That is, when the execution arrives at the function call, the | ||
function is called, it returns a single value, and that's it. This assumption | ||
allows Rust to perform many optimizations. | ||
|
||
However, some `extern` functions like [`setjmp`] and [`vfork`] can return | ||
multiple times. | ||
|
||
The `#[ffi_returns_twice]` attribute specifies that an `extern` function might | ||
returns multiple times, inhibiting optimizations that assume that this is never | ||
the case. | ||
|
||
[`setjmp`]: https://en.cppreference.com/w/cpp/utility/program/setjmp | ||
[`longjmp`]: https://en.cppreference.com/w/cpp/utility/program/longjmp | ||
[`vfork`]: http://man7.org/linux/man-pages/man2/vfork.2.html | ||
|
||
# Guide-level and reference-level explanation | ||
[guide-level-explanation]: #guide-level-explanation | ||
|
||
The `#[ffi_returns_twice]` function attribute specifies that an `extern` function | ||
might return multiple times, disabling optimizations that are incorrect for such | ||
functions. Two examples of such functions are [`setjmp`] and [`vfork`]. | ||
|
||
# Drawbacks | ||
[drawbacks]: #drawbacks | ||
|
||
This complicates the language creating a new kind of functions. | ||
|
||
# Prior art | ||
[prior-art]: #prior-art | ||
|
||
This attribute is provided in both [LLVM] and [GCC]. | ||
|
||
[LLVM]: https://llvm.org/docs/LangRef.html#id979 | ||
[GCC]: https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html | ||
|
||
# Rationale and alternatives | ||
[rationale-and-alternatives]: #rationale-and-alternatives | ||
|
||
In some platforms, efficient implementations of standard library APIs have to | ||
call low-level platform APIs that return multiple times. For example, the | ||
widely-used [`musl`] library implements [`posix_spawn`] on Linux by calling | ||
[`vfork`] (see: [`musl` blog post]). Rust implementations of such libraries (for | ||
example, see: [`steed`]) should be able to call these platform interfaces | ||
without invoking undefined behavior. | ||
|
||
This RFC introduces a function attribute that disables incorrect optimizations | ||
only for those functions for which they would be incorrect. | ||
|
||
One alternative could be to remove the assumption that Rust functions return at | ||
most once, eliminating the need for this attribute. This would have negative | ||
performance implications for most Rust functions, which do not return multiple | ||
times, making Rust functions a non-zero-cost abstraction. | ||
|
||
Another alternative could be to not support interfacing with this type of | ||
platform APIs, requiring users to use a different programming language (C, | ||
Assembly, etc.) to do so. | ||
|
||
[`posix_spawn`]: http://man7.org/linux/man-pages/man3/posix_spawn.3.html | ||
[`musl`]: https://www.musl-libc.org/ | ||
[`musl` blog post]: https://ewontfix.com/7/ | ||
[`steed`]: https://github.com/japaric/steed | ||
|
||
# Unresolved questions | ||
[unresolved-questions]: #unresolved-questions | ||
|
||
Is this attribute sufficient to make write programs with functions that return | ||
multiple times possible? | ||
|
||
# Future possibilities | ||
[future-possibilities]: #future-possibilities | ||
|
||
This RFC attempts to make writing programs that interface with extern functions | ||
that return multiple times possible, but doing so is very challenging because it | ||
is trivial to introduce undefined behavior in those programs. | ||
|
||
Future RFCs could try to make it easier to avoid certain types of undefined | ||
behavior. For example, we could extend the borrow checker to take | ||
`#[ffi_returns_twice]` into account and reject programs that would have | ||
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 | ||
invoking constructors. We could also explore diagnosing these cases. | ||
|
||
[`Drop`]: https://doc.rust-lang.org/std/ops/trait.Drop.html | ||
[`Pin`]: https://doc.rust-lang.org/std/pin/struct.Pin.html |