Skip to content
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

Merged
merged 2 commits into from
Nov 13, 2023

Conversation

Zalathar
Copy link
Contributor

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.

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.
@rustbot
Copy link
Collaborator

rustbot commented Nov 12, 2023

r? @davidtwco

(rustbot has picked a reviewer for you, use r? to override)

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Nov 12, 2023
@rustbot
Copy link
Collaborator

rustbot commented Nov 12, 2023

Some changes occurred to MIR optimizations

cc @rust-lang/wg-mir-opt

@Zalathar
Copy link
Contributor Author

@rustbot label +A-code-coverage +beta-nominated

This works around a reported stable-to-beta regression.

@rustbot rustbot added A-code-coverage Area: Source-based code coverage (-Cinstrument-coverage) beta-nominated Nominated for backporting to the compiler in the beta channel. labels Nov 12, 2023
@Zalathar

This comment was marked as outdated.

Comment on lines +384 to +389
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;
}
Copy link
Contributor Author

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.

Copy link
Contributor

@Swatinem Swatinem left a 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?

@Zalathar
Copy link
Contributor Author

The main obstacle to writing a test is that currently I can only reproduce the issue via a standalone workspace that depends on abi_stable. So far I haven't been able to write a test that reproduces the issue.

If I investigate more, I might learn enough about the trigger conditions to be able to come up with a useful test.

@Zalathar
Copy link
Contributor Author

I still haven't been able to reproduce the llvm-cov failure in a test, but I was able to write a test that demonstrates a more benign form of the problem. Here's what happens if the workaround is not applied:

   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 macro_that_defines_a_function and spills over into the subsequent comment. In #117788, that span spills over into a subsequent file, so the line number for the end of the span is less than the line number of its start; that's what causes llvm-cov to exit with an error.

@davidtwco
Copy link
Member

The main obstacle to writing a test is that currently I can only reproduce the issue via a standalone workspace that depends on abi_stable. So far I haven't been able to write a test that reproduces the issue.

If I investigate more, I might learn enough about the trigger conditions to be able to come up with a useful test.

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.

Copy link
Member

@davidtwco davidtwco left a 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.

@Zalathar
Copy link
Contributor Author

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.

@davidtwco
Copy link
Member

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.

@davidtwco davidtwco added beta-accepted Accepted for backporting to the compiler in the beta channel. and removed beta-nominated Nominated for backporting to the compiler in the beta channel. labels Nov 13, 2023
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.)
@Zalathar Zalathar force-pushed the bogus-macro-name-span branch from 829893e to 514e324 Compare November 13, 2023 01:34
@Zalathar
Copy link
Contributor Author

@davidtwco I tried putting the macro in a separate auxiliary crate and was able to reproduce the full llvm-cov failure; good call on that one. I've pushed an updated test.

@davidtwco
Copy link
Member

@bors r+

@bors
Copy link
Contributor

bors commented Nov 13, 2023

📌 Commit 514e324 has been approved by davidtwco

It is now in the queue for this repository.

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Nov 13, 2023
bors added a commit to rust-lang-ci/rust that referenced this pull request Nov 13, 2023
…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`
@bors
Copy link
Contributor

bors commented Nov 13, 2023

⌛ Testing commit 514e324 with merge b5cdb96...

@bors
Copy link
Contributor

bors commented Nov 13, 2023

☀️ Test successful - checks-actions
Approved by: davidtwco
Pushing b5cdb96 to master...

@bors bors added the merged-by-bors This PR was explicitly merged by bors. label Nov 13, 2023
@bors bors merged commit b5cdb96 into rust-lang:master Nov 13, 2023
12 checks passed
@rustbot rustbot added this to the 1.76.0 milestone Nov 13, 2023
@rust-timer
Copy link
Collaborator

Finished benchmarking commit (b5cdb96): comparison URL.

Overall result: no relevant changes - no action needed

@rustbot label: -perf-regression

Instruction count

This benchmark run did not return any relevant results for this metric.

Max RSS (memory usage)

Results

This 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.

mean range count
Regressions ❌
(primary)
0.8% [0.4%, 1.5%] 3
Regressions ❌
(secondary)
- - 0
Improvements ✅
(primary)
- - 0
Improvements ✅
(secondary)
-0.7% [-0.7%, -0.7%] 2
All ❌✅ (primary) 0.8% [0.4%, 1.5%] 3

Cycles

Results

This 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.

mean range count
Regressions ❌
(primary)
0.5% [0.4%, 0.6%] 2
Regressions ❌
(secondary)
- - 0
Improvements ✅
(primary)
-0.5% [-0.5%, -0.5%] 1
Improvements ✅
(secondary)
- - 0
All ❌✅ (primary) 0.2% [-0.5%, 0.6%] 3

Binary size

This benchmark run did not return any relevant results for this metric.

Bootstrap: 674.078s -> 673.401s (-0.10%)
Artifact size: 311.07 MiB -> 311.12 MiB (0.02%)

@cuviper
Copy link
Member

cuviper commented Nov 17, 2023

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.

davidtwco added beta-accepted and removed beta-nominated labels

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!
@rustbot label +beta-nominated

@rustbot rustbot added the beta-nominated Nominated for backporting to the compiler in the beta channel. label Nov 17, 2023
@Zalathar
Copy link
Contributor Author

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.)

@Zalathar Zalathar deleted the bogus-macro-name-span branch November 18, 2023 01:25
@Mark-Simulacrum Mark-Simulacrum removed the beta-nominated Nominated for backporting to the compiler in the beta channel. label Nov 18, 2023
@Mark-Simulacrum Mark-Simulacrum modified the milestones: 1.76.0, 1.75.0 Nov 18, 2023
bors added a commit to rust-lang-ci/rust that referenced this pull request Nov 18, 2023
…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`
bors added a commit to rust-lang-ci/rust that referenced this pull request Dec 6, 2023
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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-code-coverage Area: Source-based code coverage (-Cinstrument-coverage) beta-accepted Accepted for backporting to the compiler in the beta channel. merged-by-bors This PR was explicitly merged by bors. S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants