-
Notifications
You must be signed in to change notification settings - Fork 13.3k
Stabilize naked_functions
#134213
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Stabilize naked_functions
#134213
Conversation
Some changes occurred in src/doc/unstable-book/src/compiler-flags/sanitizer.md cc @rust-lang/project-exploit-mitigations, @rcvalle This PR modifies cc @jieyouxu rust-analyzer is developed in its own repository. If possible, consider making this change to rust-lang/rust-analyzer instead. cc @rust-lang/rust-analyzer Some changes occurred in compiler/rustc_codegen_cranelift cc @bjorn3 |
☔ The latest upstream changes (presumably #134395) made this pull request unmergeable. Please resolve the merge conflicts. |
6183807
to
ed0d0b9
Compare
ed0d0b9
to
ae2fa18
Compare
r? lang |
This probably needs a new lang FCP since the old one is probably outdated (the implementation of naked function has changed signficantly). |
Thanks for the thorough report @folkertdev! @rfcbot fcp merge |
Team member @tmandry has proposed to merge this. The next step is review by the rest of the tagged team members: Concerns:
Once a majority of reviewers approve (and at most 2 approvals are outstanding), this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up! cc @rust-lang/lang-advisors: FCP proposed for lang, please feel free to register concerns. |
Actually, @rust-lang/libs-api does this need your FCP? I think the path of |
The final comment period, with a disposition to merge, as per the review above, is now complete. As the automated representative of the governance process, I would like to thank the author for their work and everyone else who contributed. This will be merged soon. |
☔ The latest upstream changes (presumably #139555) made this pull request unmergeable. Please resolve the merge conflicts. |
…gross35 Allow (but don't require) `#[unsafe(naked)]` so that `compiler-builtins` can upgrade to it tracking issue: rust-lang#138997 Per rust-lang#134213 (comment), we want to make the `#[naked]` attribute an unsafe attribute. Making that change runs into a cyclic dependency with `compiler-builtins` which uses `#[naked]`, where `rustc` needs an updated `compiler-builtins` and vice versa. So based on rust-lang#139753 and [#t-compiler/help > updating &rust-lang#96;compiler-builtins&rust-lang#96; and &rust-lang#96;rustc&rust-lang#96;](https://rust-lang.zulipchat.com/#narrow/channel/182449-t-compiler.2Fhelp/topic/updating.20.60compiler-builtins.60.20and.20.60rustc.60), this PR allows, but does not require `#[unsafe(naked)]`, and makes that change for some of the tests to check that both `#[naked]` and `#[unsafe(naked)]` are accepted. Then we can upgrade and synchronize `compiler-builtins`, and then make `#[naked]` (without `unsafe`) invalid. r? `@traviscross` (or someone from t-compiler if you're faster and this look allright)
…gross35 Allow (but don't require) `#[unsafe(naked)]` so that `compiler-builtins` can upgrade to it tracking issue: rust-lang#138997 Per rust-lang#134213 (comment), we want to make the `#[naked]` attribute an unsafe attribute. Making that change runs into a cyclic dependency with `compiler-builtins` which uses `#[naked]`, where `rustc` needs an updated `compiler-builtins` and vice versa. So based on rust-lang#139753 and [#t-compiler/help > updating &rust-lang#96;compiler-builtins&rust-lang#96; and &rust-lang#96;rustc&rust-lang#96;](https://rust-lang.zulipchat.com/#narrow/channel/182449-t-compiler.2Fhelp/topic/updating.20.60compiler-builtins.60.20and.20.60rustc.60), this PR allows, but does not require `#[unsafe(naked)]`, and makes that change for some of the tests to check that both `#[naked]` and `#[unsafe(naked)]` are accepted. Then we can upgrade and synchronize `compiler-builtins`, and then make `#[naked]` (without `unsafe`) invalid. r? ``@traviscross`` (or someone from t-compiler if you're faster and this look allright)
Rollup merge of rust-lang#139797 - folkertdev:naked-allow-unsafe, r=tgross35 Allow (but don't require) `#[unsafe(naked)]` so that `compiler-builtins` can upgrade to it tracking issue: rust-lang#138997 Per rust-lang#134213 (comment), we want to make the `#[naked]` attribute an unsafe attribute. Making that change runs into a cyclic dependency with `compiler-builtins` which uses `#[naked]`, where `rustc` needs an updated `compiler-builtins` and vice versa. So based on rust-lang#139753 and [#t-compiler/help > updating &rust-lang#96;compiler-builtins&rust-lang#96; and &rust-lang#96;rustc&rust-lang#96;](https://rust-lang.zulipchat.com/#narrow/channel/182449-t-compiler.2Fhelp/topic/updating.20.60compiler-builtins.60.20and.20.60rustc.60), this PR allows, but does not require `#[unsafe(naked)]`, and makes that change for some of the tests to check that both `#[naked]` and `#[unsafe(naked)]` are accepted. Then we can upgrade and synchronize `compiler-builtins`, and then make `#[naked]` (without `unsafe`) invalid. r? `@traviscross` (or someone from t-compiler if you're faster and this look allright)
I, too, would prefer to write the above. I'm concerned though, that this may be inconsistent with other uses of #[unsafe(no_mangle)]
pub fn example() { /* Are we within `unsafe` scope here? */ } (The If the answer is 'yes', then this is proposal is consistent and I'm in support. But if not, this seems inconsistent with other Thoughts? |
In a sense, yes, we are. If we write, #[unsafe(no_mangle)]
pub extern "C" fn malloc(x: isize) -> *mut c_void { .. } then whether the resulting program is valid is going to necessarily depend on the body of that function. Even if we don't use It's similar here. Removing the function prelude, like stepping on |
On the procedurals here, @folkertdev, I've been watching with interest the dance we're doing in:
Once this is all settled, please give this PR a @tgross35: Since you've been involved in those steps, I'd be interested in seeing your approving review on the implementation details of this PR. And, @Amanieu, as always on asm-related matters, I'd be interested to see your approving review here as well. Once it's ready, I'll give it a final look over myself and, if it has these approving reviews, give it the |
I did take a thorough look at this before and it all seems correct to my knowledge. I'll re-review once #139753 lands, but I am very much +1 on having this stabilized. The only usage comment I have is that it would be nice if we could |
I just found this rust/compiler/rustc_passes/src/check_attr.rs Lines 693 to 699 in 191df20
There are similar comments on a number of other attributes, but is this something that could/should be fixed as we stabilize this attribute? |
Good catch. Yes. Specifically, this is a hard error currently (without the feature flag): struct S {
#[naked] //~ ERROR
field: (),
} I can't imagine that we'd want this to become allowed on stable due to us stabilizing |
I'm surprised about some of the other places this exception is made also in the code. I can't imagine that we want it for |
cc #80564 |
…ttribute, r=tgross35,traviscross Make `#[naked]` an unsafe attribute tracking issue: rust-lang#138997 Per rust-lang#134213 (comment), the `#[naked]` attribute is now an unsafe attribute (in any edition). This can only be merged when the above PRs are merged, I'd just like to see if there are any CI surprises here, and maybe there is early review feedback too. r? `@traviscross`
The stabilization PR LGTM, so r=me. |
02cff1f
to
f087806
Compare
Some changes occurred in compiler/rustc_passes/src/check_attr.rs |
…ttribute, r=tgross35,traviscross Make `#[naked]` an unsafe attribute tracking issue: rust-lang#138997 Per rust-lang#134213 (comment), the `#[naked]` attribute is now an unsafe attribute (in any edition). This can only be merged when the above PRs are merged, I'd just like to see if there are any CI surprises here, and maybe there is early review feedback too. r? ``@traviscross``
tracking issue: #90957
request for stabilization on tracking issue: #90957 (comment)
reference PR: rust-lang/reference#1689
Request for Stabilization
Two years later, we're ready to try this again. Even though this issue is already marked as having passed FCP, given the amount of time that has passed and the changes in implementation strategy, we should follow the process again.
Summary
The
naked_functions
feature has two main parts: the#[naked]
function attribute, and thenaked_asm!
macro.An example of a naked function:
When the
#[naked]
attribute is applied to a function, the compiler won't emit a function prologue or epilogue when generating code for this function. This attribute is analogous to__attribute__((naked))
in C. The use of this feature allows the programmer to have precise control over the assembly that is generated for a given function.The body of a naked function must consist of a single
naked_asm!
invocation, a heavily restricted variant of theasm!
macro: the only legal operands areconst
andsym
, and the only legal options areraw
andatt_syntax
. In lieu of specifying operands, thenaked_asm!
within a naked function relies on the function's calling convention to determine the validity of registers.Documentation
The Rust Reference: rust-lang/reference#1689
(Previous PR: rust-lang/reference#1153)
Tests
pub
,#[no_mangle]
and#[linkage = "..."]
work correctly for naked functionsnaked_asm!
, etcInteraction with other (unstable) features
fn_align
Combining
#[naked]
with#[repr(align(N))]
works well, and is tested e.g. hereIt's tested extensively because we do need to explicitly support the
repr(align)
attribute (and make sure we e.g. don't mistake powers of two for number of bytes).History
This feature was originally proposed in RFC 1201, filed on 2015-07-10 and accepted on 2016-03-21. Support for this feature was added in #32410, landing on 2016-03-23. Development languished for several years as it was realized that the semantics given in RFC 1201 were insufficiently specific. To address this, a minimal subset of naked functions was specified by RFC 2972, filed on 2020-08-07 and accepted on 2021-11-16. Prior to the acceptance of RFC 2972, all of the stricter behavior specified by RFC 2972 was implemented as a series of warn-by-default lints that would trigger on existing uses of the
naked
attribute; these lints became hard errors in #93153 on 2022-01-22. As a result, today RFC 2972 has completely superseded RFC 1201 in describing the semantics of thenaked
attribute.More recently, the
naked_asm!
macro was added to replace the earlier use of a heavily restrictedasm!
invocation. Thenaked_asm!
name is clearer in error messages, and provides a place for documenting the specific requirements of inline assembly in naked functions.The implementation strategy was changed to emitting a global assembly block. In effect, an extern function
is emitted as something similar to
The codegen approach was chosen over the llvm naked function attribute because:
Finally, there is now an allow list of compatible attributes on naked functions, so that e.g.
#[inline]
is rejected with an error. The#[target_feature]
attribute on naked functions was later made separately unstable, because implementing it is complex and we did not want to block naked functions themselves on how target features work on them. See also #138568.relevant PRs for these recent changes
#[naked]
: report incompatible attributes #127853naked_asm!
macro for use in#[naked]
functions #128651#[naked]
functions using global asm #128004naked_functions_target_feature
unstable feature #138570Various historical notes
noreturn
RFC 2972 mentions that naked functions
Instead of
asm!
, the current implementation mandates that the body contain a singlenaked_asm!
statement. Thenaked_asm!
macro is a heavily restricted version of theasm!
macro, making it easier to talk about and document the rules of assembly in naked functions and give dedicated error messages.For
naked_asm!
, the behavior of theasm!
'snoreturn
option is implicit. Thenoreturn
option means that it is UB for control flow to fall through the end of the assembly block. Withasm!
, this option is usually used for blocks that diverge (and thus have no return and can be typed as!
). Withnaked_asm!
, the intent is different: usually naked funtions do return, but they must do so from within the assembly block. Thenoreturn
option was used so that the compiler would not itself also insert aret
instruction at the very end.padding /
ud2
A
naked_asm!
block that violates the safety assumption that control flow must not fall through the end of the assembly block is UB. Because no return instruction is emitted, whatever bytes follow the naked function will be executed, resulting in truly undefined behavior. There has been discussion whether rustc should emit an invalid instruction (e.g.ud2
on x86) after thenaked_asm!
block to at least fail early in the case of an invalidnaked_asm!
. It was however decided that it is more useful to guarantee that#[naked]
functions NEVER contain any instructions besides those in thenaked_asm!
block.unresolved questions
None
r? @Amanieu
I've validated the tests on x86_64 and aarch64