Skip to content

Commit fbb2d96

Browse files
committed
coverage: Run-make regression test for #[derive(arbitrary::Arbitrary)]
1 parent f8e355c commit fbb2d96

File tree

5 files changed

+165
-0
lines changed

5 files changed

+165
-0
lines changed

src/tools/run-make-support/src/external_deps/llvm.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,13 @@ pub fn llvm_profdata() -> LlvmProfdata {
1717
LlvmProfdata::new()
1818
}
1919

20+
/// Constructs a new `llvm-cov` invocation.
21+
/// This assumes that `llvm-cov` is available at `$LLVM_BIN_DIR/llvm-cov`.
22+
#[track_caller]
23+
pub fn llvm_cov() -> LlvmCov {
24+
LlvmCov::new()
25+
}
26+
2027
/// Construct a new `llvm-filecheck` invocation. This assumes that `llvm-filecheck` is available
2128
/// at `$LLVM_FILECHECK`.
2229
#[track_caller]
@@ -86,6 +93,13 @@ pub struct LlvmProfdata {
8693
cmd: Command,
8794
}
8895

96+
/// An `llvm-cov` invocation builder.
97+
#[derive(Debug)]
98+
#[must_use]
99+
pub struct LlvmCov {
100+
cmd: Command,
101+
}
102+
89103
/// A `llvm-filecheck` invocation builder.
90104
#[derive(Debug)]
91105
#[must_use]
@@ -151,6 +165,7 @@ pub struct LlvmObjcopy {
151165

152166
crate::macros::impl_common_helpers!(LlvmReadobj);
153167
crate::macros::impl_common_helpers!(LlvmProfdata);
168+
crate::macros::impl_common_helpers!(LlvmCov);
154169
crate::macros::impl_common_helpers!(LlvmFilecheck);
155170
crate::macros::impl_common_helpers!(LlvmObjdump);
156171
crate::macros::impl_common_helpers!(LlvmAr);
@@ -259,6 +274,17 @@ impl LlvmProfdata {
259274
}
260275
}
261276

277+
impl LlvmCov {
278+
/// Constructs a new `llvm-cov` invocation.
279+
/// This assumes that `llvm-cov` is available at `$LLVM_BIN_DIR/llvm-cov`.
280+
#[track_caller]
281+
pub fn new() -> Self {
282+
let llvm_cov = llvm_bin_dir().join("llvm-cov");
283+
let cmd = Command::new(llvm_cov);
284+
Self { cmd }
285+
}
286+
}
287+
262288
impl LlvmFilecheck {
263289
/// Construct a new `llvm-filecheck` invocation. This assumes that `llvm-filecheck` is available
264290
/// at `$LLVM_FILECHECK`.
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
# This file is automatically @generated by Cargo.
2+
# It is not intended for manual editing.
3+
version = 4
4+
5+
[[package]]
6+
name = "arbitrary"
7+
version = "1.4.1"
8+
source = "registry+https://github.com/rust-lang/crates.io-index"
9+
checksum = "dde20b3d026af13f561bdd0f15edf01fc734f0dafcedbaf42bba506a9517f223"
10+
dependencies = [
11+
"derive_arbitrary",
12+
]
13+
14+
[[package]]
15+
name = "coverage-arbitrary"
16+
version = "0.0.0"
17+
dependencies = [
18+
"arbitrary",
19+
]
20+
21+
[[package]]
22+
name = "derive_arbitrary"
23+
version = "1.4.1"
24+
source = "registry+https://github.com/rust-lang/crates.io-index"
25+
checksum = "30542c1ad912e0e3d22a1935c290e12e8a29d704a420177a31faad4a601a0800"
26+
dependencies = [
27+
"proc-macro2",
28+
"quote",
29+
"syn",
30+
]
31+
32+
[[package]]
33+
name = "proc-macro2"
34+
version = "1.0.95"
35+
source = "registry+https://github.com/rust-lang/crates.io-index"
36+
checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
37+
dependencies = [
38+
"unicode-ident",
39+
]
40+
41+
[[package]]
42+
name = "quote"
43+
version = "1.0.40"
44+
source = "registry+https://github.com/rust-lang/crates.io-index"
45+
checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
46+
dependencies = [
47+
"proc-macro2",
48+
]
49+
50+
[[package]]
51+
name = "syn"
52+
version = "2.0.104"
53+
source = "registry+https://github.com/rust-lang/crates.io-index"
54+
checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40"
55+
dependencies = [
56+
"proc-macro2",
57+
"quote",
58+
"unicode-ident",
59+
]
60+
61+
[[package]]
62+
name = "unicode-ident"
63+
version = "1.0.18"
64+
source = "registry+https://github.com/rust-lang/crates.io-index"
65+
checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
[workspace]
2+
resolver = "2"
3+
4+
[package]
5+
name = "coverage-arbitrary-crate"
6+
edition = "2024"
7+
8+
[dependencies]
9+
arbitrary = { version = "1.4.1", features = ["derive"] }
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
//! Regression test for edge-case bugs in coverage instrumentation that have
2+
//! historically been triggered by derived `arbitrary::Arbitrary` impls.
3+
//!
4+
//! See <https://github.com/rust-lang/rust/issues/141577#issuecomment-3120667286>
5+
//! for an example of one such bug.
6+
7+
use run_make_support::{cargo, is_windows, llvm};
8+
9+
fn main() {
10+
let profraw_path = "default.profraw";
11+
let profdata_path = "default.profdata";
12+
13+
// Build and run the crate with coverage instrumentation,
14+
// producing a `.profraw` file.
15+
let run_out = cargo()
16+
.args(&["run", "--manifest-path=Cargo.toml", "--release"])
17+
.env("RUSTFLAGS", "-Cinstrument-coverage")
18+
.env("LLVM_PROFILE_FILE", profraw_path)
19+
.run();
20+
21+
// The program prints its own executable path (i.e. args[0]) to stdout.
22+
let exe_path = run_out.stdout_utf8().lines().next().unwrap().to_owned();
23+
24+
// Convert `.profraw` output to `.profdata`, as needed by `llvm-cov`.
25+
llvm::llvm_profdata()
26+
.args(&["merge", "--sparse", "--output", profdata_path, profraw_path])
27+
.run();
28+
29+
// The contents of the coverage report are not very important;
30+
// what matters is that `llvm-cov` should not encounter an error
31+
// (e.g. "malformed instrumentation profile data: function name is empty").
32+
llvm::llvm_cov()
33+
.args(&["show", "-format=text", "-instr-profile", profdata_path, "-object", &exe_path])
34+
.run();
35+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
use core::hint::black_box;
2+
use std::env::args;
3+
4+
use arbitrary::{Arbitrary, Unstructured};
5+
6+
#[derive(Debug, Arbitrary)]
7+
struct MyStruct {
8+
_x: u32,
9+
}
10+
11+
#[derive(Debug, Arbitrary)]
12+
enum MyEnum {
13+
One,
14+
Two,
15+
Three,
16+
}
17+
18+
fn main() {
19+
// Print the executable path to stdout, so that the rmake script has easy
20+
// access to it. This is easier than trying to interrogate cargo.
21+
println!("{}", args().nth(0).unwrap());
22+
23+
dbg!(MyStruct::size_hint(0));
24+
dbg!(MyEnum::size_hint(0));
25+
26+
let mut data = Unstructured::new(black_box(&[0; 1024]));
27+
28+
dbg!(MyStruct::arbitrary(&mut data));
29+
dbg!(MyEnum::arbitrary(&mut data));
30+
}

0 commit comments

Comments
 (0)