Skip to content

coverage: Run-make regression test for #[derive(arbitrary::Arbitrary)] #144571

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

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions src/tools/run-make-support/src/external_deps/llvm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,13 @@ pub fn llvm_profdata() -> LlvmProfdata {
LlvmProfdata::new()
}

/// Constructs a new `llvm-cov` invocation.
/// This assumes that `llvm-cov` is available at `$LLVM_BIN_DIR/llvm-cov`.
#[track_caller]
pub fn llvm_cov() -> LlvmCov {
LlvmCov::new()
}

/// Construct a new `llvm-filecheck` invocation. This assumes that `llvm-filecheck` is available
/// at `$LLVM_FILECHECK`.
#[track_caller]
Expand Down Expand Up @@ -86,6 +93,13 @@ pub struct LlvmProfdata {
cmd: Command,
}

/// An `llvm-cov` invocation builder.
#[derive(Debug)]
#[must_use]
pub struct LlvmCov {
cmd: Command,
}

/// A `llvm-filecheck` invocation builder.
#[derive(Debug)]
#[must_use]
Expand Down Expand Up @@ -151,6 +165,7 @@ pub struct LlvmObjcopy {

crate::macros::impl_common_helpers!(LlvmReadobj);
crate::macros::impl_common_helpers!(LlvmProfdata);
crate::macros::impl_common_helpers!(LlvmCov);
crate::macros::impl_common_helpers!(LlvmFilecheck);
crate::macros::impl_common_helpers!(LlvmObjdump);
crate::macros::impl_common_helpers!(LlvmAr);
Expand Down Expand Up @@ -259,6 +274,17 @@ impl LlvmProfdata {
}
}

impl LlvmCov {
/// Constructs a new `llvm-cov` invocation.
/// This assumes that `llvm-cov` is available at `$LLVM_BIN_DIR/llvm-cov`.
#[track_caller]
pub fn new() -> Self {
let llvm_cov = llvm_bin_dir().join("llvm-cov");
let cmd = Command::new(llvm_cov);
Self { cmd }
}
}

impl LlvmFilecheck {
/// Construct a new `llvm-filecheck` invocation. This assumes that `llvm-filecheck` is available
/// at `$LLVM_FILECHECK`.
Expand Down
65 changes: 65 additions & 0 deletions tests/run-make/coverage-arbitrary/Cargo.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4

[[package]]
name = "arbitrary"
version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dde20b3d026af13f561bdd0f15edf01fc734f0dafcedbaf42bba506a9517f223"
dependencies = [
"derive_arbitrary",
]

[[package]]
name = "coverage-arbitrary"
version = "0.0.0"
dependencies = [
"arbitrary",
]

[[package]]
name = "derive_arbitrary"
version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "30542c1ad912e0e3d22a1935c290e12e8a29d704a420177a31faad4a601a0800"
dependencies = [
"proc-macro2",
"quote",
"syn",
]

[[package]]
name = "proc-macro2"
version = "1.0.95"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
dependencies = [
"unicode-ident",
]

[[package]]
name = "quote"
version = "1.0.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
dependencies = [
"proc-macro2",
]

[[package]]
name = "syn"
version = "2.0.104"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]

[[package]]
name = "unicode-ident"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
9 changes: 9 additions & 0 deletions tests/run-make/coverage-arbitrary/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[workspace]
resolver = "2"

[package]
name = "coverage-arbitrary-crate"
edition = "2024"

[dependencies]
arbitrary = { version = "1.4.1", features = ["derive"] }
Comment on lines +8 to +9
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remark: this is subject to the same consideration as #128733. Maybe at least pin this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was wondering how the other run-make cargo tests deal with these concerns, but I guess the answer is that they don't. 😱

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, unfortunately...

37 changes: 37 additions & 0 deletions tests/run-make/coverage-arbitrary/rmake.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
//! Regression test for edge-case bugs in coverage instrumentation that have
//! historically been triggered by derived `arbitrary::Arbitrary` impls.
//!
//! See <https://github.com/rust-lang/rust/issues/141577#issuecomment-3120667286>
//! for an example of one such bug.

//@ needs-profiler-runtime

use run_make_support::{cargo, is_windows, llvm};

fn main() {
let profraw_path = "default.profraw";
let profdata_path = "default.profdata";

// Build and run the crate with coverage instrumentation,
// producing a `.profraw` file.
let run_out = cargo()
.args(&["run", "--manifest-path=Cargo.toml", "--release"])
.env("RUSTFLAGS", "-Cinstrument-coverage")
.env("LLVM_PROFILE_FILE", profraw_path)
.run();

// The program prints its own executable path (i.e. args[0]) to stdout.
let exe_path = run_out.stdout_utf8().lines().next().unwrap().to_owned();

// Convert `.profraw` output to `.profdata`, as needed by `llvm-cov`.
llvm::llvm_profdata()
.args(&["merge", "--sparse", "--output", profdata_path, profraw_path])
.run();

// The contents of the coverage report are not very important;
// what matters is that `llvm-cov` should not encounter an error
// (e.g. "malformed instrumentation profile data: function name is empty").
llvm::llvm_cov()
.args(&["show", "-format=text", "-instr-profile", profdata_path, "-object", &exe_path])
.run();
}
30 changes: 30 additions & 0 deletions tests/run-make/coverage-arbitrary/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
use core::hint::black_box;
use std::env::args;

use arbitrary::{Arbitrary, Unstructured};

#[derive(Debug, Arbitrary)]
struct MyStruct {
_x: u32,
}

#[derive(Debug, Arbitrary)]
enum MyEnum {
One,
Two,
Three,
}

fn main() {
// Print the executable path to stdout, so that the rmake script has easy
// access to it. This is easier than trying to interrogate cargo.
println!("{}", args().nth(0).unwrap());

dbg!(MyStruct::size_hint(0));
dbg!(MyEnum::size_hint(0));

let mut data = Unstructured::new(black_box(&[0; 1024]));

dbg!(MyStruct::arbitrary(&mut data));
dbg!(MyEnum::arbitrary(&mut data));
}
Loading