-
Notifications
You must be signed in to change notification settings - Fork 12.9k
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
Lint against named asm labels #87324
Conversation
r? @davidtwco (rust-highfive has picked a reviewer for you, use r? to override) |
r? @Amanieu |
I decided to initially make this a deny-by-default lint because the use of named labels is almost always wrong. The RFC even says that only GAS style labels should be used. However I think it could be important to be able to be disabled if a user really understands what that means. This could be made warn by default (which I don't think is a good idea, named labels are objectively wrong) or a hard error though. |
This comment has been minimized.
This comment has been minimized.
8f18f8c
to
3222c6b
Compare
Whoops, had some git issues and seemingly didn't rebase that file right when trying to fix things |
"do not use named labels in inline assembly", | ||
BuiltinLintDiagnostics::NamedAsmLabel("Only GAS local labels of the form `N:` where N is a number may be used in inline asm".to_string()), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would word this slightly differently:
"do not use named labels in inline assembly", | |
BuiltinLintDiagnostics::NamedAsmLabel("Only GAS local labels of the form `N:` where N is a number may be used in inline asm".to_string()), | |
"avoid using named labels in inline assembly", | |
BuiltinLintDiagnostics::NamedAsmLabel("Only GAS local labels of the form `N:` where N is a number should be used in inline asm".to_string()), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure if you missed my comment or if you prefer sticking to the existing wording.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've incorporated this and also made the help a little more concise
This comment has been minimized.
This comment has been minimized.
I think it's right that that fails, technically, but that makes that test hard to do. What should I do, allow the lint there? |
Yes, just allow the lint there. |
☔ The latest upstream changes (presumably #87296) made this pull request unmergeable. Please resolve the merge conflicts. |
28dd531
to
5bed7c8
Compare
☔ The latest upstream changes (presumably #87381) made this pull request unmergeable. Please resolve the merge conflicts. |
5bed7c8
to
6ca8373
Compare
☔ The latest upstream changes (presumably #87026) made this pull request unmergeable. Please resolve the merge conflicts. |
for span in spans.into_iter() { | ||
ecx.parse_sess().buffer_lint_with_diagnostic( | ||
lint::builtin::NAMED_ASM_LABELS, | ||
span, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
buffer_lint_with_diagnostic
can take a Vec<Span>
so that we can emit a single lint for all the labels in an asm!
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh neat I didn't realize that was what MultiSpan
meant, though it seems pretty obvious in hindsight and I should have checked the impls for it. That looks a lot cleaner.
ecx.current_expansion.lint_node_id, | ||
"avoid using named labels in inline assembly", | ||
BuiltinLintDiagnostics::NamedAsmLabel("only local labels of the form `<number>:` should be used in inline asm".to_string()), | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Avoid the code duplication if the span is the only difference between the two calls.
(sorry about the late review, I thought that I submitted it last week but apparently something went wrong and it just got buffered) |
@Amanieu @bjorn3 While I definitely think we want a lint similar to this, I wish it had gone through some broader review before merging. We awoke this morning to find our CI/CD broken because of this lint erroring on local symbolic labels (i.e. https://docs.oracle.com/cd/E19120-01/open.solaris/817-5477/esqaq/index.html The motivation for this patch is to prevent emitting conflicting entries to the object file's symbol table. Numeric labels don't cause this problem and are therefore allowed. But this patch additionally disables the use of local symbolic labels which also don't cause this problem and these should be allowed too. This lint breaks the compilation of existing, working and valid code. I propose that this patch be reverted until it allows local symbolic labels. |
Actually local labels ( |
@Amanieu This still seems to me like hammering a nail with a sledge hammer.
|
|
The lint should specify that local named labels are unsupported outside naked functions.
I concede this point.
I'd have to think through the implications of that. Would it mean that developers couldn't change this to an error for naked functions? However, this PR still breaks existing, valid code and should be reverted until the implications of this change are properly understood and the semantics are agreed upon. |
Apart from naked functions, it has never been valid to use named labels, even before this PR. A future LLVM version or other backend may cause this to break at any point. The point of this PR is exactly to prevent people from writing seemingly valid, but not actually valid inline assembly. I agree that it makes sense to disable this lint for naked functions though, but I don't think it warrants a revert of this PR, thus an extension to disable the lint for naked functions.
The inline asm RFC has already defined it as not allowed: https://rust-lang.github.io/rfcs/2873-inline-asm.html
Apart from naked functions I don't think there are any edge cases where it would be fine to allow named asm labels. If there are, an issue can be opened and a solution can be discussed. As |
@bjorn3 Which still means that this PR breaks existing, valid code in the case of naked functions. That is, a change in one feature has broken valid code in another feature. The implementor of the (now broken) feature wasn't consulted and is being asked to scramble to fix the breakage or live with it. This isn't contributor friendly. It should be the responsibility of the PR author to fix breakage in other features caused by the PR. Ideally, this should be caught before merge. But when it isn't, how should we handle it? I would argue that it is still the responsibility of the PR author to fix the breakage. And the only way, procedurally, that we can enforce this is to revert the PR and reopen it. |
I agree with bjorn on all 3 points. Rust makes no stability guarantees about unstable features, and it is allowed and there is precedent to entirely change unstable features. If someone must rely on a nightly feature never changing, they should pin the nightly version to a specific, known working version, and update with caution, until the feature is stabilized. I was not aware that |
Agreed completely.
I think the main question is who does this work and when. Reverting the PR gives us breathing room to figure this out and coordinate across features. |
I believe that should never is not a guarantee, just a very strong recommendation, so I don't think this can be relied on. Even if there is that undocumented behavior to the |
If it does turn out that we can rely on this behavior of |
Naked functions MUST NOT ever be inlined. If there is some undefined behavior that causes one to be inlined, it is a bug that should be fixed. When I disabled inlining for naked functions, I did not implement it as desugaring to |
Then this is a shortcoming of LLVM, it doesn't seem to have a way to specify "no never inline this ever, if you do this is wrong". The best is |
I think naked functions can still be inlined if and only if you ensure that you setup all registers and the stack anyway as if you would actually do a real call. This is a silly thing to do, but indistinguishable from a real call except that it would duplicate the inline asm and possibly avoid a single call instruction in favor of falling through to the naked function. |
At this point I'm fairly confident that we can guarantee that |
@bjorn3 There are possibly other invariants as well (depending on platform). But while it is theoretically possible to inline a naked function, the complexity of this problem is too difficult and with too little gain. Therefore, in the Constrained Naked RFC, we commit the compiler to never inlining a naked function. This may be a promise the compiler cannot (currently) keep. But that might change in the future. And in the meantime, we clearly communicate that no one should ever depend on this behavior and can reliably depend on the opposite behavior. |
If we are advising users to not depend on naked functions being never inlined, shouldn't this lint still activate then, since the compiler cannot currently promise that? |
@asquared31415 Per the Constrained Naked Functions RFC we are advising users to depend on naked functions never being inlined. |
Oh I misinterpreted your previous statement then. I thought I still think it is possible that LLVM changes in the future to actually inline things that are |
@asquared31415 I'm sure that if LLVM adds functionality to inline even those functions, the next thing people will ask for is a way to disable it. |
Also the linter is triggered on comments: #[naked]
pub unsafe extern "sysv64" fn _start() -> ! {
asm!("
nop # here is a comment about syscall
nop // and another syscall comment
jmp syscall
hlt
.global syscall
syscall:
hlt
",
options(noreturn)
);
} gives:
|
The lint triggers on the label definition ( |
@haraldh please file a separate issue about that, it's a lot easier to track the issues that way I was not aware that platform specific comments existed, I tried to make sure that I wasn't missing platform specific behavior, but must have missed that anyway. |
This adds a deny-by-default lint to prevent the use of named labels in inline
asm!
. Without a solution to #81088 about whether the compiler should rewrite named labels or a special syntax for labels, a lint against them should prevent users from writing assembly that could break for internal compiler reasons, such as inlining or anything else that could change the number of actual inline assembly blocks emitted.This does not resolve the issue with rewriting labels, that still needs a decision if the compiler should do any more work to try to make them work.