-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Fix large_stack_frames
FP on compiler generated targets
#15101
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?
Conversation
rustbot has assigned @samueltardieu. Use |
// Don't lint compiler-generated targets | ||
if fn_span.is_dummy() { | ||
return; | ||
} | ||
|
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.
Comparing against the dummy span feels too specific. Why not return from the beginning of the function if entire_fn_span.from_expansion()
is true?
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 don't think it is a good idea to ignore macros in this lint
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.
Can you produce a realistic test case in which a macro should not be ignored and would get a sensible message? Right now, checking for entire_fn_span.from_expansion()
or using your proposed change makes no difference in tests results.
And if the goal is to lint all functions to ensure that a given stack size is not exceeded, maybe compiler generated functions should be checked after all instead of being silently ignored, and the message fixed. One could also add a configuration option to exclude test methods from the lint, that would be my preferred option.
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.
maybe compiler generated functions should be checked after all instead of being silently ignored, and the message fixed. One could also add a configuration option to exclude test methods from the lint, that would be my preferred option.
Adding @y21 to the discussion as they are currently working on this lint.
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 agree for adding configuration option for test methods. As for compiler generated functions, I'm not sure whether we should ignore it or not. I doubt if we can give a sensible error message, and even if we can, it would be hard for the user to fix it.
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.
Hm, I'm a bit torn on this one. When I initially implemented the lint, the idea was to catch functions that allocate so much stack space that they almost certainly always instantly overflow the stack when called, or are seriously at risk for it. So like most other correctness lints, I think it'd still make sense to lint some macro generated code, since you'd probably still want to know about those functions in your program.
Here's a real world example where a function is generated by a macro that this lint would catch: https://docs.rs/hex/latest/src/hex/lib.rs.html#206
The invocation from_hex_array_impl! { 4294967296 }
generates a function that creates a [u8; 4294967296]
.
So I'd prefer to still lint macro generated functions.
I am honestly a bit surprised about the linked issue. Surely they don't literally run with stack-size-threshold = 0
in a real project. I'd expect these compiler generated functions to use mostly constant or very little stack space.
So I think it's fine to ignore compiler generated functions with a dummy span like this. Any other span, like a span from a macro, at least has enough context for the user that they know where to put an #[expect]
to silence the lint
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.
In this case, should external macros be filtered or not? For example, in the current test case
#[derive(serde::Deserialize, serde::Serialize)]
struct S {
a: [u128; 31],
}
will lint, and also this one:
proc_macros::external! {
fn foo() {
println!("Hello, world!");
}
}
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 personally say it still makes sense to lint external macros. It seems useful to get a warning if there's any function that could accidentally overflow the stack regardless of where it comes from (to the best of its abilities ofc, it will always have some FNs)
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.
r? @y21 given their ongoing work on this topic.
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.
Thought a bit more about it and yeah I think I'm fine with this specifically only ignoring dummy spans. I'd ideally like this lint to warn any function regardless of where it comes from, but if there's nowhere where people can put lint level attrs for a test harness' main function, it means they'd need to have a global #![cfg_attr(test, allow(...))]
which seems unfortunate (and as I've mentioned before, it seems rather unlikely that triggering in such a function would actually represent a real problem anyway?), so lgtm
@profetia @samueltardieu @y21 thank you! |
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.
Could you add a short comment at the top of the file that this is specifically testing the test harness' compiler-generated main
function which has a dummy span? Might not be immediately obvious to someone looking at this
@@ -0,0 +1,16 @@ | |||
error: this function may allocate 88 bytes on the stack |
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 think this might lead to spurious failures when test suite is run on a 32 bit machine since fmt::Arguments
is gonna have a different size (I believe this happens at least in r-l/r if not also here in clippy when trying to merge).
The existing test file already normalizes away differing digits for pointer sizes in the stderr like this:
//@ normalize-stderr-test: "\b10000(08|16|32)\b" -> "100$$PTR" |
But, given that this is (I assume) mainly just testing that we don't emit a warning, we can just use //@check-pass
and remove the main
fn so that there's just no output.
@@ -0,0 +1,15 @@ | |||
//@compile-flags: --test | |||
#![allow(unused)] |
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 don't think this is needed. -Aunused
is always passed to uitest
// Don't lint compiler-generated targets | ||
if fn_span.is_dummy() { | ||
return; | ||
} | ||
|
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.
Thought a bit more about it and yeah I think I'm fine with this specifically only ignoring dummy spans. I'd ideally like this lint to warn any function regardless of where it comes from, but if there's nowhere where people can put lint level attrs for a test harness' main function, it means they'd need to have a global #![cfg_attr(test, allow(...))]
which seems unfortunate (and as I've mentioned before, it seems rather unlikely that triggering in such a function would actually represent a real problem anyway?), so lgtm
Closes #15099
The compiler will generate a special
main
function for the tests, which caused this FP.changelog: [
large_stack_frames
] fix FP on compiler generated targets