-
Notifications
You must be signed in to change notification settings - Fork 12.8k
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
coverage: Avoid creating malformed macro name spans #117827
Conversation
This method is trying to detect macro invocations, so that it can split a span into two parts just after the `!` of the invocation. Under some circumstances (probably involving nested macros), it gets confused and produces a span that is larger than the original span, and possibly extends outside its enclosing function and even into an adjacent file. In extreme cases, that can result in malformed coverage mappings that cause `llvm-cov` to fail. For now, we at least want to detect these egregious cases and avoid them, so that coverage reports can still be produced.
r? @davidtwco (rustbot has picked a reviewer for you, use r? to override) |
Some changes occurred to MIR optimizations cc @rust-lang/wg-mir-opt |
@rustbot label +A-code-coverage +beta-nominated This works around a reported stable-to-beta regression. |
This comment was marked as outdated.
This comment was marked as outdated.
if self.curr().span.lo() + after_macro_bang > self.curr().span.hi() { | ||
// Something is wrong with the macro name span; | ||
// return now to avoid emitting malformed mappings. | ||
// FIXME(#117788): Track down why this happens. | ||
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.
Even though curr
is already available as a local variable, the change that extracted that variable isn't part of the current (1.74) beta branch. So instead I'm calling self.curr()
explicitly here, so that the same lines of code can simply be copied over to beta if desired.
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.
it would be nice to have a regression test for this. I assume creating one while keeping this PR beta-backportable might be a problem though, considering you were merging/cleaning up the coverage tests in the meantime?
The main obstacle to writing a test is that currently I can only reproduce the issue via a standalone workspace that depends on If I investigate more, I might learn enough about the trigger conditions to be able to come up with a useful test. |
I still haven't been able to reproduce the LL| |// edition: 2021
LL| |
LL| |// Regression test for <https://github.com/rust-lang/rust/issues/117788>.
LL| |// Under some circumstances, the heuristics that detect macro name spans can
LL| |// get confused and produce incorrect spans beyond the bounds of the span
LL| |// being processed.
LL| |
LL| 1|fn main() {
LL| 1| affected_function();
LL| 1|}
LL| |
LL| |macro_rules! macro_that_defines_a_function {
LL| | (fn $name:ident () $body:tt) => {
LL| 1| fn $name () -> () $body
LL| 1| }
LL| 1|}
LL| 1|
LL| 1|// These comment lines are not executable and should not have counters.
LL| |// If they do have counters, it means that a span from the above $body has
LL| |// been extended beyond its proper bounds.
LL| |
LL| |macro_rules! macro_with_an_unreasonably_and_egregiously_long_name {
LL| | () => {
LL| | println!("hello");
LL| | };
LL| |}
LL| |
LL| |macro_that_defines_a_function! {
LL| | fn affected_function() {
LL| | macro_with_an_unreasonably_and_egregiously_long_name!();
LL| | }
LL| |} Notice that there is a span of “executable” code that extends outside of |
Is there a reason you can't write a test with multiple crates containing the reproduction from #117788? Here's the compiletest docs for auxiliary crates if that's helpful - though it may just be a limitation of the coverage test suite that I'm unaware of. |
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.
This patch seems good to me, r=me if the MCVE test can't be added.
I'll try a version that puts the macro in an auxiliary crate, and see if I can get it to reproduce the full failure instead of the lesser problem. |
I don't have a good sense of what the priority of the issue being resolved is, but given that the release is this week and this won't be visited by a triage meeting, I'm going to unilaterally backport approve this - it's a very simple patch which I think has little risk of introducing new bugs. |
Without the workaround applied, this test will produce malformed mappings that cause `llvm-cov` to fail. (And if it does emit well-formed mappings, they should be obviously incorrect.)
829893e
to
514e324
Compare
@davidtwco I tried putting the macro in a separate auxiliary crate and was able to reproduce the full |
@bors r+ |
…Simulacrum [stable] Prepare 1.74.0 release https://forge.rust-lang.org/release/process.html#promote-branches-t-3-days-monday Also backports: * Disabling specialization as an alternative backport of "Fix excessive initialization and reads beyond EOF in io::copy(_, Vec<u8>) specialization rust-lang#117576" * coverage: Avoid creating malformed macro name spans rust-lang#117827 r? `@Mark-Simulacrum`
☀️ Test successful - checks-actions |
Finished benchmarking commit (b5cdb96): comparison URL. Overall result: no relevant changes - no action needed@rustbot label: -perf-regression Instruction countThis benchmark run did not return any relevant results for this metric. Max RSS (memory usage)ResultsThis is a less reliable metric that may be of interest but was not used to determine the overall result at the top of this comment.
CyclesResultsThis is a less reliable metric that may be of interest but was not used to determine the overall result at the top of this comment.
Binary sizeThis benchmark run did not return any relevant results for this metric. Bootstrap: 674.078s -> 673.401s (-0.10%) |
Procedural note: we keep both labels on to signal that it's approved, and only drop the nomination after someone (usually on the release team) has actually done the backport. Since this PR landed in 1.76, and was backported to 1.74 during its beta->stable (#117843), then I assume we still do need it for 1.75-beta as well. If you want to reconsider the approval in a triage meeting, feel free to drop beta-accepted for now! |
Note for whoever applies this to the 1.75 beta branch: take the patches from this PR since they should apply cleanly. (The patches that were applied to stable needed some trivial adjustments that are not relevant to 1.75.) |
…mulacrum [beta] backport & bootstrap bump Bumps the bootstrap compiler to released 1.74, and lands the first backport: - rust-lang#117827: coverage: Avoid creating malformed macro name spans r? `@Mark-Simulacrum`
coverage: Be more strict about what counts as a "visible macro" This is a follow-up to the workaround in rust-lang#117827, and I believe it now properly fixes rust-lang#117788. The old code treats a span as having a “visible macro” if it is part of a macro-expansion, and its parent callsite's context is the same as the body span's context. But if the body span is itself part of an expansion, the macro in question might not actually be visible from the body span. That results in the macro name's length being meaningless as a span offset. We now only consider spans whose parent callsite is the same as the source callsite, i.e. the parent has no parent. --- I've also included some related cleanup for the code added by rust-lang#117827. That code was more complicated than normal, because I wanted it to be easy to backport to stable/beta.
This is a workaround for #117788. It detects a particular scenario where we would create malformed coverage spans that might cause
llvm-cov
to immediately exit with an error, preventing the user from processing coverage reports.The patch has been kept as simple as possible so that it's trivial to backport to beta (or stable) if desired.
The
maybe_push_macro_name_span
method is trying to detect macro invocations, so that it can split a span into two parts just after the!
of the invocation.Under some circumstances (probably involving nested macros), it gets confused and produces a span that is larger than the original span, and possibly extends outside its enclosing function and even into an adjacent file.
In extreme cases, that can result in malformed coverage mappings that cause
llvm-cov
to fail. For now, we at least want to detect these egregious cases and avoid them, so that coverage reports can still be produced.