Skip to content

Commit d6acad5

Browse files
committed
Add an attribute to indicate that a function might return multiple times
1 parent 1ab8c3c commit d6acad5

File tree

1 file changed

+108
-0
lines changed

1 file changed

+108
-0
lines changed

text/0000-returns-twice.md

+108
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
- Feature Name: ffi-returns-twice
2+
- Start Date: 2019.02.08
3+
- RFC PR: (leave this empty)
4+
- Rust Issue: (leave this empty)
5+
6+
# Summary
7+
[summary]: #summary
8+
9+
This RFC adds a new function attribute, `#[ffi_returns_twice]`, which indicates
10+
that an `extern` function can return multiple times.
11+
12+
# Motivation
13+
[motivation]: #motivation
14+
15+
Rust assumes that function calls like:
16+
17+
```rust
18+
let x = foo();
19+
```
20+
21+
return only once. That is, when the execution arrives at the function call, the
22+
function is called, it returns a single value, and that's it. This assumption
23+
allows Rust to perform many optimizations.
24+
25+
However, some `extern` functions like [`setjmp`] and [`vfork`] can return
26+
multiple times.
27+
28+
The `#[ffi_returns_twice]` attribute specifies that an `extern` function might
29+
returns multiple times, inhibiting optimizations that assume that this is never
30+
the case.
31+
32+
[`setjmp`]: https://en.cppreference.com/w/cpp/utility/program/setjmp
33+
[`longjmp`]: https://en.cppreference.com/w/cpp/utility/program/longjmp
34+
[`vfork`]: http://man7.org/linux/man-pages/man2/vfork.2.html
35+
36+
# Guide-level and reference-level explanation
37+
[guide-level-explanation]: #guide-level-explanation
38+
39+
The `#[ffi_returns_twice]` function attribute specifies that an `extern` function
40+
might return multiple times, disabling optimizations that are incorrect for such
41+
functions. Two examples of such functions are [`setjmp`] and [`vfork`].
42+
43+
# Drawbacks
44+
[drawbacks]: #drawbacks
45+
46+
This complicates the language creating a new kind of functions.
47+
48+
# Prior art
49+
[prior-art]: #prior-art
50+
51+
This attribute is provided in both [LLVM] and [GCC].
52+
53+
[LLVM]: https://llvm.org/docs/LangRef.html#id979
54+
[GCC]: https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html
55+
56+
# Rationale and alternatives
57+
[rationale-and-alternatives]: #rationale-and-alternatives
58+
59+
In some platforms, efficient implementations of standard library APIs have to
60+
call low-level platform APIs that return multiple times. For example, the
61+
widely-used [`musl`] library implements [`posix_spawn`] on Linux by calling
62+
[`vfork`] (see: [`musl` blog post]). Rust implementations of such libraries (for
63+
example, see: [`steed`]) should be able to call these platform interfaces
64+
without invoking undefined behavior.
65+
66+
This RFC introduces a function attribute that disables incorrect optimizations
67+
only for those functions for which they would be incorrect.
68+
69+
One alternative could be to remove the assumption that Rust functions return at
70+
most once, eliminating the need for this attribute. This would have negative
71+
performance implications for most Rust functions, which do not return multiple
72+
times, making Rust functions a non-zero-cost abstraction.
73+
74+
Another alternative could be to not support interfacing with this type of
75+
platform APIs, requiring users to use a different programming language (C,
76+
Assembly, etc.) to do so.
77+
78+
[`posix_spawn`]: http://man7.org/linux/man-pages/man3/posix_spawn.3.html
79+
[`musl`]: https://www.musl-libc.org/
80+
[`musl` blog post]: https://ewontfix.com/7/
81+
[`steed`]: https://github.com/japaric/steed
82+
83+
# Unresolved questions
84+
[unresolved-questions]: #unresolved-questions
85+
86+
Is this attribute sufficient to make write programs with functions that return
87+
multiple times possible?
88+
89+
# Future possibilities
90+
[future-possibilities]: #future-possibilities
91+
92+
This RFC attempts to make writing programs that interface with extern functions
93+
that return multiple times possible, but doing so is very challenging because it
94+
is trivial to introduce undefined behavior in those programs.
95+
96+
Future RFCs could try to make it easier to avoid certain types of undefined
97+
behavior. For example, we could extend the borrow checker to take
98+
`#[ffi_returns_twice]` into account and reject programs that would have
99+
undefined behavior of the type "use-after-move".
100+
101+
In the presence of types that implement `Drop`, usage of APIs that return
102+
multiple times requires extreme care to avoid deallocating [`Drop`] types
103+
without calling `Drop::drop`. Calling `Drop::drop` before freeing the memory of
104+
a `Drop` type is required for the correctness of APIs like [`Pin`]. Future RFCs
105+
could pursue warning when it is clear that this might occur.
106+
107+
`Drop`]: https://doc.rust-lang.org/std/ops/trait.Drop.html
108+
[`Pin`]: https://doc.rust-lang.org/std/pin/struct.Pin.html

0 commit comments

Comments
 (0)