Auto merge of #117827 - Zalathar:bogus-macro-name-span, r=davidtwco

coverage: Avoid creating malformed macro name spans

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 commit is contained in:
bors 2023-11-13 06:16:27 +00:00
commit b5cdb9631f
5 changed files with 96 additions and 0 deletions

View File

@ -381,6 +381,12 @@ impl<'a> CoverageSpansGenerator<'a> {
let merged_prefix_len = self.curr_original_span.lo() - curr.span.lo();
let after_macro_bang = merged_prefix_len + BytePos(visible_macro.as_str().len() as u32 + 1);
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;
}
let mut macro_name_cov = curr.clone();
self.curr_mut().span = curr.span.with_lo(curr.span.lo() + after_macro_bang);
macro_name_cov.span =

View File

@ -0,0 +1,10 @@
// edition: 2021
#[macro_export]
macro_rules! macro_that_defines_a_function {
(fn $name:ident () $body:tt) => {
fn $name () -> () $body
}
}
// Non-executable comment.

View File

@ -0,0 +1,16 @@
Function name: macro_name_span::affected_function
Raw bytes (9): 0x[01, 01, 00, 01, 01, 06, 1b, 00, 20]
Number of files: 1
- file 0 => global file 1
Number of expressions: 0
Number of file 0 mappings: 1
- Code(Counter(0)) at (prev + 6, 27) to (start + 0, 32)
Function name: macro_name_span::main
Raw bytes (9): 0x[01, 02, 00, 01, 01, 0b, 01, 02, 02]
Number of files: 1
- file 0 => global file 2
Number of expressions: 0
Number of file 0 mappings: 1
- Code(Counter(0)) at (prev + 11, 1) to (start + 2, 2)

View File

@ -0,0 +1,39 @@
$DIR/auxiliary/macro_name_span_helper.rs:
LL| |// edition: 2021
LL| |
LL| |#[macro_export]
LL| |macro_rules! macro_that_defines_a_function {
LL| | (fn $name:ident () $body:tt) => {
LL| 1| fn $name () -> () $body
LL| | }
LL| |}
LL| |
LL| |// Non-executable comment.
$DIR/macro_name_span.rs:
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| |// aux-build: macro_name_span_helper.rs
LL| |extern crate macro_name_span_helper;
LL| |
LL| 1|fn main() {
LL| 1| affected_function();
LL| 1|}
LL| |
LL| |macro_rules! macro_with_an_unreasonably_and_egregiously_long_name {
LL| | () => {
LL| | println!("hello");
LL| | };
LL| |}
LL| |
LL| |macro_name_span_helper::macro_that_defines_a_function! {
LL| | fn affected_function() {
LL| | macro_with_an_unreasonably_and_egregiously_long_name!();
LL| | }
LL| |}

View File

@ -0,0 +1,25 @@
// edition: 2021
// Regression test for <https://github.com/rust-lang/rust/issues/117788>.
// Under some circumstances, the heuristics that detect macro name spans can
// get confused and produce incorrect spans beyond the bounds of the span
// being processed.
// aux-build: macro_name_span_helper.rs
extern crate macro_name_span_helper;
fn main() {
affected_function();
}
macro_rules! macro_with_an_unreasonably_and_egregiously_long_name {
() => {
println!("hello");
};
}
macro_name_span_helper::macro_that_defines_a_function! {
fn affected_function() {
macro_with_an_unreasonably_and_egregiously_long_name!();
}
}