coverage: Regression test for "function name is empty" bug

The bug was triggered by a particular usage of the `?` try operator in a
proc-macro expansion.

Thanks to lqd for the minimization.

Co-authored-by: Rémy Rakic <remy.rakic+github@gmail.com>
This commit is contained in:
Zalathar
2025-07-29 10:29:32 +10:00
parent 498ae9fed2
commit 7ca4d1f6a1
8 changed files with 266 additions and 0 deletions

View File

@@ -0,0 +1,31 @@
//@ edition: 2024
// (The proc-macro crate doesn't need to be instrumented.)
//@ compile-flags: -Cinstrument-coverage=off
use proc_macro::TokenStream;
/// Minimized form of `#[derive(arbitrary::Arbitrary)]` that still triggers
/// the original bug.
const CODE: &str = "
impl Arbitrary for MyEnum {
fn try_size_hint() -> Option<usize> {
Some(0)?;
None
}
}
";
#[proc_macro_attribute]
pub fn attr(_attr: TokenStream, _item: TokenStream) -> TokenStream {
CODE.parse().unwrap()
}
#[proc_macro]
pub fn bang(_item: TokenStream) -> TokenStream {
CODE.parse().unwrap()
}
#[proc_macro_derive(Arbitrary)]
pub fn derive_arbitrary(_item: TokenStream) -> TokenStream {
CODE.parse().unwrap()
}

View File

@@ -0,0 +1,20 @@
Function name: <try_in_macro::MyEnum as try_in_macro::Arbitrary>::try_size_hint
Raw bytes (9): 0x[01, 01, 00, 01, 00, 1e, 2a, 00, 2b]
Number of files: 1
- file 0 => $DIR/try-in-macro.rs
Number of expressions: 0
Number of file 0 mappings: 1
- Code(Zero) at (prev + 30, 42) to (start + 0, 43)
Highest counter ID seen: (none)
Function name: try_in_macro::main
Raw bytes (19): 0x[01, 01, 00, 03, 01, 29, 01, 00, 0a, 01, 01, 05, 00, 1a, 01, 01, 01, 00, 02]
Number of files: 1
- file 0 => $DIR/try-in-macro.rs
Number of expressions: 0
Number of file 0 mappings: 3
- Code(Counter(0)) at (prev + 41, 1) to (start + 0, 10)
- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 26)
- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2)
Highest counter ID seen: c0

View File

@@ -0,0 +1,44 @@
LL| |//! Regression test for <https://github.com/rust-lang/rust/issues/141577>.
LL| |//!
LL| |//! The changes in <https://github.com/rust-lang/rust/pull/144298> exposed a
LL| |//! latent bug that would sometimes cause the compiler to emit a covfun record
LL| |//! for a function, but not emit a corresponding PGO symbol name entry, because
LL| |//! the function did not have any physical coverage counters. The `llvm-cov`
LL| |//! tool would then fail to resolve the covfun record's function name hash,
LL| |//! and exit with the cryptic error:
LL| |//!
LL| |//! ```text
LL| |//! malformed instrumentation profile data: function name is empty
LL| |//! ```
LL| |//!
LL| |//! The bug was then triggered in the wild by the macro-expansion of
LL| |//! `#[derive(arbitrary::Arbitrary)]`.
LL| |//!
LL| |//! This test uses a minimized form of the `Arbitrary` derive macro that was
LL| |//! found to still trigger the original bug. The bug could also be triggered
LL| |//! by a bang proc-macro or an attribute proc-macro.
LL| |
LL| |//@ edition: 2024
LL| |//@ revisions: attr bang derive
LL| |//@ proc-macro: try_in_macro_helper.rs
LL| |
LL| |trait Arbitrary {
LL| | fn try_size_hint() -> Option<usize>;
LL| |}
LL| |
LL| |// Expand via an attribute proc-macro.
LL| |#[cfg_attr(attr, try_in_macro_helper::attr)]
LL| |const _: () = ();
LL| |
LL| |// Expand via a regular bang-style proc-macro.
LL| |#[cfg(bang)]
LL| |try_in_macro_helper::bang!();
LL| |
LL| |// Expand via a derive proc-macro.
LL| |#[cfg_attr(derive, derive(try_in_macro_helper::Arbitrary))]
LL| |enum MyEnum {}
LL| |
LL| 1|fn main() {
LL| 1| MyEnum::try_size_hint();
LL| 1|}

View File

@@ -0,0 +1,20 @@
Function name: <try_in_macro::MyEnum as try_in_macro::Arbitrary>::try_size_hint
Raw bytes (9): 0x[01, 01, 00, 01, 00, 23, 1c, 00, 1d]
Number of files: 1
- file 0 => $DIR/try-in-macro.rs
Number of expressions: 0
Number of file 0 mappings: 1
- Code(Zero) at (prev + 35, 28) to (start + 0, 29)
Highest counter ID seen: (none)
Function name: try_in_macro::main
Raw bytes (19): 0x[01, 01, 00, 03, 01, 29, 01, 00, 0a, 01, 01, 05, 00, 1a, 01, 01, 01, 00, 02]
Number of files: 1
- file 0 => $DIR/try-in-macro.rs
Number of expressions: 0
Number of file 0 mappings: 3
- Code(Counter(0)) at (prev + 41, 1) to (start + 0, 10)
- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 26)
- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2)
Highest counter ID seen: c0

View File

@@ -0,0 +1,44 @@
LL| |//! Regression test for <https://github.com/rust-lang/rust/issues/141577>.
LL| |//!
LL| |//! The changes in <https://github.com/rust-lang/rust/pull/144298> exposed a
LL| |//! latent bug that would sometimes cause the compiler to emit a covfun record
LL| |//! for a function, but not emit a corresponding PGO symbol name entry, because
LL| |//! the function did not have any physical coverage counters. The `llvm-cov`
LL| |//! tool would then fail to resolve the covfun record's function name hash,
LL| |//! and exit with the cryptic error:
LL| |//!
LL| |//! ```text
LL| |//! malformed instrumentation profile data: function name is empty
LL| |//! ```
LL| |//!
LL| |//! The bug was then triggered in the wild by the macro-expansion of
LL| |//! `#[derive(arbitrary::Arbitrary)]`.
LL| |//!
LL| |//! This test uses a minimized form of the `Arbitrary` derive macro that was
LL| |//! found to still trigger the original bug. The bug could also be triggered
LL| |//! by a bang proc-macro or an attribute proc-macro.
LL| |
LL| |//@ edition: 2024
LL| |//@ revisions: attr bang derive
LL| |//@ proc-macro: try_in_macro_helper.rs
LL| |
LL| |trait Arbitrary {
LL| | fn try_size_hint() -> Option<usize>;
LL| |}
LL| |
LL| |// Expand via an attribute proc-macro.
LL| |#[cfg_attr(attr, try_in_macro_helper::attr)]
LL| |const _: () = ();
LL| |
LL| |// Expand via a regular bang-style proc-macro.
LL| |#[cfg(bang)]
LL| |try_in_macro_helper::bang!();
LL| |
LL| |// Expand via a derive proc-macro.
LL| |#[cfg_attr(derive, derive(try_in_macro_helper::Arbitrary))]
LL| |enum MyEnum {}
LL| |
LL| 1|fn main() {
LL| 1| MyEnum::try_size_hint();
LL| 1|}

View File

@@ -0,0 +1,20 @@
Function name: <try_in_macro::MyEnum as try_in_macro::Arbitrary>::try_size_hint
Raw bytes (9): 0x[01, 01, 00, 01, 00, 26, 38, 00, 39]
Number of files: 1
- file 0 => $DIR/try-in-macro.rs
Number of expressions: 0
Number of file 0 mappings: 1
- Code(Zero) at (prev + 38, 56) to (start + 0, 57)
Highest counter ID seen: (none)
Function name: try_in_macro::main
Raw bytes (19): 0x[01, 01, 00, 03, 01, 29, 01, 00, 0a, 01, 01, 05, 00, 1a, 01, 01, 01, 00, 02]
Number of files: 1
- file 0 => $DIR/try-in-macro.rs
Number of expressions: 0
Number of file 0 mappings: 3
- Code(Counter(0)) at (prev + 41, 1) to (start + 0, 10)
- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 26)
- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2)
Highest counter ID seen: c0

View File

@@ -0,0 +1,44 @@
LL| |//! Regression test for <https://github.com/rust-lang/rust/issues/141577>.
LL| |//!
LL| |//! The changes in <https://github.com/rust-lang/rust/pull/144298> exposed a
LL| |//! latent bug that would sometimes cause the compiler to emit a covfun record
LL| |//! for a function, but not emit a corresponding PGO symbol name entry, because
LL| |//! the function did not have any physical coverage counters. The `llvm-cov`
LL| |//! tool would then fail to resolve the covfun record's function name hash,
LL| |//! and exit with the cryptic error:
LL| |//!
LL| |//! ```text
LL| |//! malformed instrumentation profile data: function name is empty
LL| |//! ```
LL| |//!
LL| |//! The bug was then triggered in the wild by the macro-expansion of
LL| |//! `#[derive(arbitrary::Arbitrary)]`.
LL| |//!
LL| |//! This test uses a minimized form of the `Arbitrary` derive macro that was
LL| |//! found to still trigger the original bug. The bug could also be triggered
LL| |//! by a bang proc-macro or an attribute proc-macro.
LL| |
LL| |//@ edition: 2024
LL| |//@ revisions: attr bang derive
LL| |//@ proc-macro: try_in_macro_helper.rs
LL| |
LL| |trait Arbitrary {
LL| | fn try_size_hint() -> Option<usize>;
LL| |}
LL| |
LL| |// Expand via an attribute proc-macro.
LL| |#[cfg_attr(attr, try_in_macro_helper::attr)]
LL| |const _: () = ();
LL| |
LL| |// Expand via a regular bang-style proc-macro.
LL| |#[cfg(bang)]
LL| |try_in_macro_helper::bang!();
LL| |
LL| |// Expand via a derive proc-macro.
LL| |#[cfg_attr(derive, derive(try_in_macro_helper::Arbitrary))]
LL| |enum MyEnum {}
LL| |
LL| 1|fn main() {
LL| 1| MyEnum::try_size_hint();
LL| 1|}

View File

@@ -0,0 +1,43 @@
//! Regression test for <https://github.com/rust-lang/rust/issues/141577>.
//!
//! The changes in <https://github.com/rust-lang/rust/pull/144298> exposed a
//! latent bug that would sometimes cause the compiler to emit a covfun record
//! for a function, but not emit a corresponding PGO symbol name entry, because
//! the function did not have any physical coverage counters. The `llvm-cov`
//! tool would then fail to resolve the covfun record's function name hash,
//! and exit with the cryptic error:
//!
//! ```text
//! malformed instrumentation profile data: function name is empty
//! ```
//!
//! The bug was then triggered in the wild by the macro-expansion of
//! `#[derive(arbitrary::Arbitrary)]`.
//!
//! This test uses a minimized form of the `Arbitrary` derive macro that was
//! found to still trigger the original bug. The bug could also be triggered
//! by a bang proc-macro or an attribute proc-macro.
//@ edition: 2024
//@ revisions: attr bang derive
//@ proc-macro: try_in_macro_helper.rs
trait Arbitrary {
fn try_size_hint() -> Option<usize>;
}
// Expand via an attribute proc-macro.
#[cfg_attr(attr, try_in_macro_helper::attr)]
const _: () = ();
// Expand via a regular bang-style proc-macro.
#[cfg(bang)]
try_in_macro_helper::bang!();
// Expand via a derive proc-macro.
#[cfg_attr(derive, derive(try_in_macro_helper::Arbitrary))]
enum MyEnum {}
fn main() {
MyEnum::try_size_hint();
}