You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: text/0000-unsafe-extern-blocks.md
+23-30Lines changed: 23 additions & 30 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -11,10 +11,7 @@ In Edition 2024 it is `unsafe` to declare an `extern` function or static, but ex
11
11
# Motivation
12
12
[motivation]: #motivation
13
13
14
-
Simply declaring extern items, even without ever using them, can cause Undefined Behavior (see, e.g., issue [#46188][]).
15
-
When performing cross-language compilation, attributes on one function declaration can flow to the foreign declaration elsewhere within LLVM and cause a miscompilation.
16
-
In Rust we consider all sources of Undefined Behavior to be `unsafe`, and so we must make declaring extern blocks be `unsafe`.
17
-
The up-side to this change is that in the new style it will be possible to declare an extern fn that's safe to call after the initial unsafe declaration.
14
+
Simply declaring extern items, even without ever using them, can cause Undefined Behavior (see, e.g., issue [#46188][]). When performing cross-language compilation, attributes on one function declaration can flow to the foreign declaration elsewhere within LLVM and cause a miscompilation. In Rust we consider all sources of Undefined Behavior to be `unsafe`, and so we must make declaring extern blocks be `unsafe`. The up-side to this change is that in the new style it will be possible to declare an extern fn that's safe to call after the initial unsafe declaration.
@@ -25,20 +22,15 @@ Rust can utilize functions and statics from foreign code that are provided durin
25
22
26
23
An `extern` block can be placed anywhere a function declaration could appear (generally at the top level of a module).
27
24
28
-
* On editions >= 2024, you *must* write all `extern` blocks as `unsafe extern`.
29
-
* On editions < 2024, you *may* write `unsafe extern`, or you can write an `extern` block without the `unsafe` keyword. Writing an `extern` block without the `unsafe` keyword is provided for compatibility only, and will eventually generate a warning.
30
-
*`unsafe extern` interacts with the `unsafe_code` lint, and a `deny` or `forbid` with that lint will deny or forbid the unsafe external block.
25
+
- On editions >= 2024, you *must* write all `extern` blocks as `unsafe extern`.
26
+
- On editions < 2024, you *may* write `unsafe extern`, or you can write an `extern` block without the `unsafe` keyword. Writing an `extern` block without the `unsafe` keyword is provided for compatibility only, and will eventually generate a warning.
27
+
-`unsafe extern` interacts with the `unsafe_code` lint, and a `deny` or `forbid` with that lint will deny or forbid the unsafe external block.
31
28
32
-
Within an `extern` block is zero or more declarations of external functions and/or external static values.
33
-
An extern function is declared with a `;` instead of a function body (similar to a method of a trait).
34
-
An extern static value is also declared with a `;` instead of an expression (similar to an associated const of a trait).
35
-
In both cases, the actual function body or value is provided by whatever external source (which is probably not even written in Rust).
29
+
Within an `extern` block is zero or more declarations of external functions and/or external static values. An extern function is declared with a `;` instead of a function body (similar to a method of a trait). An extern static value is also declared with a `;` instead of an expression (similar to an associated const of a trait). In both cases, the actual function body or value is provided by whatever external source (which is probably not even written in Rust).
36
30
37
-
When an `unsafe extern` block is used, all declarations within that `extern` block *must* have the `unsafe` or `safe` keywords as part of their signature.
38
-
The `safe` keyword is a contextual keyword; it is currently allowed only within `extern` blocks.
31
+
When an `unsafe extern` block is used, all declarations within that `extern` block *must* have the `unsafe` or `safe` keywords as part of their signature. The `safe` keyword is a contextual keyword; it is currently allowed only within `extern` blocks.
39
32
40
-
If an `extern` block is used in an older edition without the `unsafe` keyword, declarations *cannot* specify `safe` or `unsafe`.
41
-
Code must update to `unsafe extern` style blocks if it wants to make `safe` declarations.
33
+
If an `extern` block is used in an older edition without the `unsafe` keyword, declarations *cannot* specify `safe` or `unsafe`. Code must update to `unsafe extern` style blocks if it wants to make `safe` declarations.
42
34
43
35
```rust
44
36
unsafeextern {
@@ -60,19 +52,17 @@ unsafe extern {
60
52
61
53
`extern` blocks are `unsafe` because if the declaration doesn't match the actual external function, or the actual external data, then the behavior of the resulting program may be undefined.
62
54
63
-
Once they are unsafely declared, a `safe` item can be used outside the `extern` block as if it were any other safe function or static value declared within rust.
64
-
The unsafe obligation of ensuring that the correct items are being linked to is performed by the crate making the declaration, not the crate using that declaration.
55
+
Once they are unsafely declared, a `safe` item can be used outside the `extern` block as if it were any other safe function or static value declared within rust. The unsafe obligation of ensuring that the correct items are being linked to is performed by the crate making the declaration, not the crate using that declaration.
65
56
66
-
Items declared as `unsafe`*must* still have a correctly matching signature at compile time, but they *also* have some sort of additional obligation for correct usage at runtime.
67
-
They can only be used within an `unsafe` block.
57
+
Items declared as `unsafe`*must* still have a correctly matching signature at compile time, but they *also* have some sort of additional obligation for correct usage at runtime. They can only be used within an `unsafe` block.
* Editions >= 2024 *must* prefix all `extern` blocks with `unsafe`.
75
-
* Editions < 2024 *should* prefix `extern` blocks with `unsafe`, this will eventually be a warn-by-default compatibility lint when `unsafe` is missing.
64
+
- Editions >= 2024 *must* prefix all `extern` blocks with `unsafe`.
65
+
- Editions < 2024 *should* prefix `extern` blocks with `unsafe`, this will eventually be a warn-by-default compatibility lint when `unsafe` is missing.
76
66
77
67
This RFC replaces the *["functions"][]* and *["statics"][]* sections in the [external blocks][] chapter of the Rust Reference with the following:
78
68
@@ -81,32 +71,35 @@ This RFC replaces the *["functions"][]* and *["statics"][]* sections in the [ext
Functions within external blocks are declared in the same way as other Rust functions, with the exception that they must not have a body and are instead terminated by a semicolon. Patterns are not allowed in parameters, only IDENTIFIER or _ may be used. The function qualifiers `const`, `async`, and `extern` are not allowed. If the function is unsafe to call, then the function should use the `unsafe` qualifier. If the function is safe to call, then the function should use the `safe` qualifier (a contextual keyword). Functions that are not qualified as `unsafe` or `safe` are assumed to be `unsafe`.
74
+
75
+
Functions within external blocks are declared in the same way as other Rust functions, with the exception that they must not have a body and are instead terminated by a semicolon. Patterns are not allowed in parameters, only IDENTIFIER or _ may be used. The function qualifiers `const`, `async`, and `extern` are not allowed. If the function is unsafe to call, then the function should use the `unsafe` qualifier. If the function is safe to call, then the function should use the `safe` qualifier (a contextual keyword). Functions that are not qualified as `unsafe` or `safe` are assumed to be `unsafe`.
85
76
86
77
If the function signature declared in Rust is incompatible with the function signature as declared in the foreign code, the behavior of the resulting program may be undefined.
87
78
88
-
Functions within external blocks may be called by Rust code, just like functions defined in Rust. The Rust compiler will automatically use the correct foreign ABI when making the call.
79
+
Functions within external blocks may be called by Rust code, just like functions defined in Rust. The Rust compiler will automatically use the correct foreign ABI when making the call.
80
+
81
+
When coerced to a function pointer, a function declared in an extern block has type:
89
82
90
-
When coerced to a function pointer, a function declared in an extern block has type
91
83
```rust
92
84
extern"abi"for<'l1, ..., 'lm> fn(A1, ..., An) ->R
93
85
```
94
-
where `'l1`, ... `'lm` are its lifetime parameters, `A1`, ..., `An` are the declared types of its parameters and `R` is the declared return type.
86
+
where `'l1`, ...,`'lm` are its lifetime parameters, `A1`, ..., `An` are the declared types of its parameters and `R` is the declared return type.
95
87
96
88
### Statics
97
-
Statics within external blocks are declared in the same way as statics outside of external blocks, except that they do not have an expression initializing their value. If the static is unsafe to access, then the static should use the `unsafe` qualifier. If the static is safe to access (and immutable), then the static should use the `safe` qualifier (a contextual keyword). Statics that are not qualified as `unsafe` or `safe` are assumed to be `unsafe`.
98
89
99
-
Extern statics can be either immutable or mutable just like statics outside of external blocks. An immutable static must be initialized before any Rust code is executed. It is not enough for the static to be initialized before Rust code reads from it. A mutable extern static is always `unsafe` to access, the same as a Rust mutable static, and as such can not be marked with a `safe` qualifier.
90
+
Statics within external blocks are declared in the same way as statics outside of external blocks, except that they do not have an expression initializing their value. If the static is unsafe to access, then the static should use the `unsafe` qualifier. If the static is safe to access (and immutable), then the static should use the `safe` qualifier (a contextual keyword). Statics that are not qualified as `unsafe` or `safe` are assumed to be `unsafe`.
91
+
92
+
Extern statics can be either immutable or mutable just like statics outside of external blocks. An immutable static must be initialized before any Rust code is executed. It is not enough for the static to be initialized before Rust code reads from it. A mutable extern static is always `unsafe` to access, the same as a Rust mutable static, and as such can not be marked with a `safe` qualifier.
100
93
101
94
# Drawbacks
102
95
[drawbacks]: #drawbacks
103
96
104
-
This change will induce some churn. Hopefully, allowing people to safely call some foreign functions will make up for that.
97
+
This change will induce some churn. Hopefully, allowing people to safely call some foreign functions will make up for that.
Incorrect extern declarations can cause UB in current Rust, but we have no way to automatically check that all declarations are correct, nor is such a thing likely to be developed. Making the declarations `unsafe` so that programmers are aware of the dangers and can give extern blocks the attention they deserve is the minimum step.
102
+
Incorrect extern declarations can cause UB in current Rust, but we have no way to automatically check that all declarations are correct, nor is such a thing likely to be developed. Making the declarations `unsafe` so that programmers are aware of the dangers and can give extern blocks the attention they deserve is the minimum step.
110
103
111
104
# Prior art
112
105
[prior-art]: #prior-art
@@ -116,7 +109,7 @@ None we are aware of.
116
109
# Unresolved questions
117
110
[unresolved-questions]: #unresolved-questions
118
111
119
-
* Extern declarations are actually *always* unsafe and able to cause UB regardless of edition. This RFC doesn't have a specific answer on how to improve pre-2024 code.
112
+
* Extern declarations are actually *always* unsafe and able to cause UB regardless of edition. This RFC doesn't have a specific answer on how to improve pre-2024 code.
0 commit comments