Skip to content
Merged
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
4 changes: 0 additions & 4 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -122,10 +122,6 @@ jobs:
with:
cache-targets: true # cache build artifacts
cache-bin: true # cache the ~/.cargo/bin directory
- name: "Clear macOS panic-abort cache"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

thanks for coming back to this.

if: runner.os == 'macOS'
shell: bash
run: rm -rf target/panic-abort
- name: "Remove nextest CI report"
shell: bash
run: rm -rf target/nextest/ci/junit.xml
Expand Down
4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,10 @@ opt-level = 3
incremental = false
codegen-units = 1

[profile.panic-abort]
inherits = "dev"
panic = "abort"

[patch.crates-io]
# proptest pulls in a dependency on libm, which changes the runtime of some math functions
# so benchmarks are not measuring the same thing as the release build. This patch removes
Expand Down
16 changes: 7 additions & 9 deletions bin_tests/src/artifacts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,23 +18,21 @@ pub fn crashtracker_receiver(profile: BuildProfile) -> ArtifactsBuild {
}

/// Creates an ArtifactsBuild for the crashtracker_bin_test binary.
pub fn crashtracker_bin_test(profile: BuildProfile, panic_abort: bool) -> ArtifactsBuild {
pub fn crashtracker_bin_test(profile: BuildProfile) -> ArtifactsBuild {
ArtifactsBuild {
name: "crashtracker_bin_test".to_owned(),
build_profile: profile,
artifact_type: ArtifactType::Bin,
panic_abort: if panic_abort { Some(true) } else { None },
..Default::default()
}
}

/// Creates an ArtifactsBuild for the crashing_test_app binary.
pub fn crashing_app(profile: BuildProfile, panic_abort: bool) -> ArtifactsBuild {
pub fn crashing_app(profile: BuildProfile) -> ArtifactsBuild {
ArtifactsBuild {
name: "crashing_test_app".to_owned(),
build_profile: profile,
artifact_type: ArtifactType::Bin,
panic_abort: if panic_abort { Some(true) } else { None },
..Default::default()
}
}
Expand Down Expand Up @@ -79,7 +77,7 @@ pub struct StandardArtifacts {
impl StandardArtifacts {
pub fn new(profile: BuildProfile) -> Self {
Self {
crashtracker_bin: crashtracker_bin_test(profile, false),
crashtracker_bin: crashtracker_bin_test(profile),
crashtracker_receiver: crashtracker_receiver(profile),
}
}
Expand All @@ -95,17 +93,17 @@ pub fn all_prebuild_artifacts() -> Vec<ArtifactsBuild> {

// Standard artifacts for both Debug and Release profiles
for profile in [BuildProfile::Debug, BuildProfile::Release] {
artifacts.push(crashtracker_bin_test(profile, false));
artifacts.push(crashtracker_bin_test(profile));
artifacts.push(crashtracker_receiver(profile));
artifacts.push(crashtracker_unix_socket_receiver(profile));
artifacts.push(test_the_tests(profile));
artifacts.push(profiling_ffi(profile));
artifacts.push(crashing_app(profile, false));
artifacts.push(crashing_app(profile));
}

// Panic abort variants (used by panic hook tests)
artifacts.push(crashtracker_bin_test(BuildProfile::Debug, true));
artifacts.push(crashing_app(BuildProfile::Debug, true));
artifacts.push(crashtracker_bin_test(BuildProfile::PanicAbort));
artifacts.push(crashing_app(BuildProfile::PanicAbort));

artifacts
}
82 changes: 38 additions & 44 deletions bin_tests/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,27 +34,17 @@ fn get_base_target_dir() -> &'static PathBuf {
})
}

/// Returns the target directory for a specific build configuration.
/// For builds with variants (like panic_abort), returns a variant-specific subdirectory.
fn get_target_dir_for_build(c: &ArtifactsBuild) -> PathBuf {
let base = get_base_target_dir().clone();

// If this is a variant build (e.g., panic_abort), use a variant-specific target directory
if c.panic_abort == Some(true) {
base.join("panic-abort")
} else {
base
}
}

/// Computes the path where the artifact will be located after building.
pub fn compute_artifact_path(c: &ArtifactsBuild) -> anyhow::Result<PathBuf> {
let target_dir = get_target_dir_for_build(c);
let mut artifact_path = get_base_target_dir().clone();

let mut artifact_path = target_dir;
// Each profile writes to its own `target/` subdirectory. The `PanicAbort`
// profile is a custom Cargo profile, so it lives directly under
// `target/panic-abort/` rather than under `debug`/`release`.
artifact_path.push(match c.build_profile {
BuildProfile::Debug => "debug",
BuildProfile::Release => "release",
BuildProfile::PanicAbort => "panic-abort",
});

match c.artifact_type {
Expand Down Expand Up @@ -101,6 +91,12 @@ pub enum BuildProfile {
#[default]
Debug,
Release,
/// Debug opt-level built with `panic = "abort"` (via the dedicated
/// `panic-abort` Cargo profile). Used by crash-handler tests that must
/// exercise the abort path. Making this a `BuildProfile` variant — rather than
/// a separate flag — keeps illegal combinations (e.g. release + panic=abort)
/// unrepresentable.
PanicAbort,
}

#[derive(Debug, Default, PartialEq, Eq, Hash, Clone)]
Expand All @@ -110,7 +106,6 @@ pub struct ArtifactsBuild {
pub artifact_type: ArtifactType,
pub build_profile: BuildProfile,
pub triple_target: Option<String>,
pub panic_abort: Option<bool>,
}

fn cargo_build_artifact(c: &ArtifactsBuild) -> anyhow::Result<PathBuf> {
Expand All @@ -119,41 +114,40 @@ fn cargo_build_artifact(c: &ArtifactsBuild) -> anyhow::Result<PathBuf> {
let mut build_cmd = process::Command::new(env!("CARGO"));
build_cmd.arg("build");

// For variant builds (like panic_abort), use a separate target directory
// so they don't conflict with standard builds
let target_dir = get_target_dir_for_build(c);
if target_dir != *get_base_target_dir() {
build_cmd.arg("--target-dir").arg(&target_dir);
}

if let BuildProfile::Release = c.build_profile {
build_cmd.arg("--release");
match c.build_profile {
BuildProfile::Debug => {}
BuildProfile::Release => {
build_cmd.arg("--release");
}
BuildProfile::PanicAbort => {
// Build with the dedicated `panic-abort` Cargo profile (defined in the
// workspace root Cargo.toml with `panic = "abort"`), so artifacts land
// in `target/panic-abort/` under the standard target layout and
// Swatinem/rust-cache manages and cleans them like any other profile.
build_cmd.arg("--profile").arg("panic-abort");

// `-C force-unwind-tables=yes` has no profile equivalent, so it stays a
// scoped RUSTFLAG applied only to this build invocation. `panic=abort`
// strips the `.eh_frame` unwind tables that the aarch64 backtrace
// unwinder relies on; without them `RUST_BACKTRACE` can loop forever on
// certain binary layouts (rust-lang/rust#123733), hanging the test until
// the runner OOMs. Keep until #123733 (fix: rust-lang/rust#143613) ships
// in a stable toolchain.
let existing_rustflags = std::env::var("RUSTFLAGS").unwrap_or_default();
let new_rustflags = if existing_rustflags.is_empty() {
"-C force-unwind-tables=yes".to_string()
} else {
format!("{} -C force-unwind-tables=yes", existing_rustflags)
};
build_cmd.env("RUSTFLAGS", new_rustflags);
}
}

match c.artifact_type {
ArtifactType::ExecutablePackage | ArtifactType::CDylib => build_cmd.arg("-p"),
ArtifactType::Bin => build_cmd.arg("--bin"),
};

if c.panic_abort == Some(true) {
// `-C panic=abort` suppresses `.eh_frame` unwind tables, which the aarch64
// backtrace unwinder relies on; without them `RUST_BACKTRACE` can loop forever
// on certain binary layouts (rust-lang/rust#123733), hanging the test until the
// runner OOMs. Force the tables back on so backtraces terminate. This is
// layout-sensitive, so it can appear/disappear across unrelated changes; keep
// until #123733 (fix: rust-lang/rust#143613) ships in a stable toolchain.
let existing_rustflags = std::env::var("RUSTFLAGS").unwrap_or_default();
let new_rustflags = if existing_rustflags.is_empty() {
"-C panic=abort -C force-unwind-tables=yes".to_string()
} else {
format!(
"{} -C panic=abort -C force-unwind-tables=yes",
existing_rustflags
)
};
build_cmd.env("RUSTFLAGS", new_rustflags);
}

build_cmd.arg(&c.name);

let output = build_cmd.output()?;
Expand Down
10 changes: 5 additions & 5 deletions bin_tests/tests/crashtracker_bin_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1153,9 +1153,9 @@ fn test_crash_tracking_bin_segfault() {
fn test_crash_tracking_app(crash_type: &str) {
use bin_tests::test_runner::run_custom_crash_test;

// Set up custom artifacts: receiver + crashing_test_app with panic_abort
// Set up custom artifacts: receiver + crashing_test_app with panic=abort
let crashtracker_receiver = artifacts::crashtracker_receiver(BuildProfile::Release);
let crashing_app = artifacts::crashing_app(BuildProfile::Debug, true);
let crashing_app = artifacts::crashing_app(BuildProfile::PanicAbort);

let artifacts_map = fetch_built_artifacts(&[&crashtracker_receiver, &crashing_app]).unwrap();

Expand Down Expand Up @@ -1229,7 +1229,7 @@ fn test_panic_hook_mode(mode: &str, expected_category: &str, expected_panic_mess

// Set up custom artifacts: receiver + crashtracker_bin_test
let crashtracker_receiver = artifacts::crashtracker_receiver(BuildProfile::Release);
let crashtracker_bin_test = artifacts::crashtracker_bin_test(BuildProfile::Debug, true);
let crashtracker_bin_test = artifacts::crashtracker_bin_test(BuildProfile::PanicAbort);

let artifacts_map =
fetch_built_artifacts(&[&crashtracker_receiver, &crashtracker_bin_test]).unwrap();
Expand Down Expand Up @@ -1303,7 +1303,7 @@ fn test_crash_tracking_callstack() {
// Set up custom artifacts: receiver + crashing_test_app (in Debug mode)
let crashtracker_receiver = artifacts::crashtracker_receiver(BuildProfile::Release);
// compile in debug so we avoid inlining and can check the callchain
let crashing_app = artifacts::crashing_app(BuildProfile::Debug, false);
let crashing_app = artifacts::crashing_app(BuildProfile::Debug);

let artifacts_map = fetch_built_artifacts(&[&crashtracker_receiver, &crashing_app]).unwrap();

Expand Down Expand Up @@ -2508,7 +2508,7 @@ fn setup_test_fixtures<'a>(crates: &[&'a ArtifactsBuild]) -> TestFixtures<'a> {
fn setup_crashtracking_crates(
crash_tracking_receiver_profile: BuildProfile,
) -> (ArtifactsBuild, ArtifactsBuild) {
let crashtracker_bin = artifacts::crashtracker_bin_test(crash_tracking_receiver_profile, false);
let crashtracker_bin = artifacts::crashtracker_bin_test(crash_tracking_receiver_profile);
let crashtracker_receiver = artifacts::crashtracker_receiver(crash_tracking_receiver_profile);
(crashtracker_bin, crashtracker_receiver)
}
Expand Down
1 change: 0 additions & 1 deletion bin_tests/tests/test_the_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ fn test_the_tests_inner(profile: BuildProfile) {
build_profile: profile,
artifact_type: ArtifactType::CDylib,
triple_target: None,
panic_abort: None,
},
&test_the_tests,
];
Expand Down
Loading