Skip to content

Commit b5cdb96

Browse files
committed
Auto merge of rust-lang#117827 - Zalathar:bogus-macro-name-span, r=davidtwco
coverage: Avoid creating malformed macro name spans This is a workaround for rust-lang#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.
2 parents ea1e5cc + 514e324 commit b5cdb96

File tree

5 files changed

+96
-0
lines changed

5 files changed

+96
-0
lines changed

compiler/rustc_mir_transform/src/coverage/spans.rs

+6
Original file line numberDiff line numberDiff line change
@@ -381,6 +381,12 @@ impl<'a> CoverageSpansGenerator<'a> {
381381

382382
let merged_prefix_len = self.curr_original_span.lo() - curr.span.lo();
383383
let after_macro_bang = merged_prefix_len + BytePos(visible_macro.as_str().len() as u32 + 1);
384+
if self.curr().span.lo() + after_macro_bang > self.curr().span.hi() {
385+
// Something is wrong with the macro name span;
386+
// return now to avoid emitting malformed mappings.
387+
// FIXME(#117788): Track down why this happens.
388+
return;
389+
}
384390
let mut macro_name_cov = curr.clone();
385391
self.curr_mut().span = curr.span.with_lo(curr.span.lo() + after_macro_bang);
386392
macro_name_cov.span =
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// edition: 2021
2+
3+
#[macro_export]
4+
macro_rules! macro_that_defines_a_function {
5+
(fn $name:ident () $body:tt) => {
6+
fn $name () -> () $body
7+
}
8+
}
9+
10+
// Non-executable comment.
+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
Function name: macro_name_span::affected_function
2+
Raw bytes (9): 0x[01, 01, 00, 01, 01, 06, 1b, 00, 20]
3+
Number of files: 1
4+
- file 0 => global file 1
5+
Number of expressions: 0
6+
Number of file 0 mappings: 1
7+
- Code(Counter(0)) at (prev + 6, 27) to (start + 0, 32)
8+
9+
Function name: macro_name_span::main
10+
Raw bytes (9): 0x[01, 02, 00, 01, 01, 0b, 01, 02, 02]
11+
Number of files: 1
12+
- file 0 => global file 2
13+
Number of expressions: 0
14+
Number of file 0 mappings: 1
15+
- Code(Counter(0)) at (prev + 11, 1) to (start + 2, 2)
16+
+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
$DIR/auxiliary/macro_name_span_helper.rs:
2+
LL| |// edition: 2021
3+
LL| |
4+
LL| |#[macro_export]
5+
LL| |macro_rules! macro_that_defines_a_function {
6+
LL| | (fn $name:ident () $body:tt) => {
7+
LL| 1| fn $name () -> () $body
8+
LL| | }
9+
LL| |}
10+
LL| |
11+
LL| |// Non-executable comment.
12+
13+
$DIR/macro_name_span.rs:
14+
LL| |// edition: 2021
15+
LL| |
16+
LL| |// Regression test for <https://github.com/rust-lang/rust/issues/117788>.
17+
LL| |// Under some circumstances, the heuristics that detect macro name spans can
18+
LL| |// get confused and produce incorrect spans beyond the bounds of the span
19+
LL| |// being processed.
20+
LL| |
21+
LL| |// aux-build: macro_name_span_helper.rs
22+
LL| |extern crate macro_name_span_helper;
23+
LL| |
24+
LL| 1|fn main() {
25+
LL| 1| affected_function();
26+
LL| 1|}
27+
LL| |
28+
LL| |macro_rules! macro_with_an_unreasonably_and_egregiously_long_name {
29+
LL| | () => {
30+
LL| | println!("hello");
31+
LL| | };
32+
LL| |}
33+
LL| |
34+
LL| |macro_name_span_helper::macro_that_defines_a_function! {
35+
LL| | fn affected_function() {
36+
LL| | macro_with_an_unreasonably_and_egregiously_long_name!();
37+
LL| | }
38+
LL| |}
39+

tests/coverage/macro_name_span.rs

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// edition: 2021
2+
3+
// Regression test for <https://github.com/rust-lang/rust/issues/117788>.
4+
// Under some circumstances, the heuristics that detect macro name spans can
5+
// get confused and produce incorrect spans beyond the bounds of the span
6+
// being processed.
7+
8+
// aux-build: macro_name_span_helper.rs
9+
extern crate macro_name_span_helper;
10+
11+
fn main() {
12+
affected_function();
13+
}
14+
15+
macro_rules! macro_with_an_unreasonably_and_egregiously_long_name {
16+
() => {
17+
println!("hello");
18+
};
19+
}
20+
21+
macro_name_span_helper::macro_that_defines_a_function! {
22+
fn affected_function() {
23+
macro_with_an_unreasonably_and_egregiously_long_name!();
24+
}
25+
}

0 commit comments

Comments
 (0)