Skip to content

Commit 6fa12e8

Browse files
author
lukacan
committed
🔥 Additional improvements to the invariants and error handling
1 parent 122b78b commit 6fa12e8

6 files changed

Lines changed: 467 additions & 227 deletions

File tree

crates/cli/src/command/fuzz.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ pub(crate) enum FuzzCommand {
6363
long = "exit-code",
6464
required = false,
6565
value_name = "MODE",
66-
help = "Exit with non-zero code on failures. Modes: 'all' (any failure), 'invariants' (only fuzz test assertions), 'panics' (only program panics)."
66+
help = "Exit with non-zero code on failures. Modes: 'all' (any failure), 'invariants' (only custom invariant/assert failures)."
6767
)]
6868
exit_code: Option<ExitCodeMode>,
6969
#[arg(

crates/client/src/commander/mod.rs

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ pub enum Error {
2727
BuildProgramsFailed,
2828
#[error("fuzzing failed")]
2929
FuzzingFailed,
30-
#[error("Fuzzing found failing invariants or unhandled panics")]
31-
FuzzingFailedInvariantOrPanic,
30+
#[error("Fuzzing failed due to exit-code policy (invariants/all)")]
31+
FuzzingFailedPolicy,
3232
#[error("Coverage error: {0}")]
3333
Coverage(#[from] crate::coverage::CoverageError),
3434
#[error("Cannot find the trident-tests directory in the current workspace")]
@@ -120,26 +120,31 @@ impl Commander {
120120
}
121121

122122
/// Manages a child process in an async context, specifically for monitoring fuzzing tasks.
123-
/// Waits for the process to exit or a Ctrl+C signal. Prints an error message if the process
124-
/// exits with an error, and sleeps briefly on Ctrl+C. Throws `Error::FuzzingFailed` on errors.
123+
/// Waits for the process to exit or a Ctrl+C signal.
124+
///
125+
/// Exit-code semantics:
126+
/// - `0`: success
127+
/// - `99`: policy failure from fuzz runner (only treated as error when policy is enabled)
128+
/// - other non-zero: runtime failure (always treated as error)
125129
///
126130
/// # Arguments
127131
/// * `child` - A mutable reference to a `Child` process.
132+
/// * `policy_enabled` - True when `--exit-code` policy is active.
128133
///
129134
/// # Errors
130-
/// * Throws `Error::FuzzingFailed` if waiting on the child process fails.
135+
/// * Throws `Error::FuzzingFailed` or `Error::FuzzingFailedPolicy` on failure.
131136
#[throws]
132-
async fn handle_child(child: &mut Child, with_exit_code: bool) {
137+
async fn handle_child(child: &mut Child, policy_enabled: bool) {
133138
tokio::select! {
134139
res = child.wait() =>
135140
match res {
136141
Ok(status) => match status.code() {
137142
Some(code) => {
138-
match (code, with_exit_code) {
139-
(0, _) => {} // fuzzing did not find any failing invariants or panics and we dont care about exit code
140-
(99, true) => throw!(Error::FuzzingFailedInvariantOrPanic), // fuzzing found failing invariants or panics and we care about exit code
141-
(99, false) => {} // fuzzing found failing invariants or panics and we dont care about exit code
142-
(_, _) => throw!(Error::FuzzingFailed), // fuzzing failed for some other reason so we care about exit code
143+
match (code, policy_enabled) {
144+
(0, _) => {}
145+
(99, true) => throw!(Error::FuzzingFailedPolicy),
146+
(99, false) => {}
147+
(_, _) => throw!(Error::FuzzingFailed),
143148
}
144149
}
145150
None => throw!(Error::FuzzingFailed),

crates/client/src/exit_code.rs

Lines changed: 5 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,15 @@ use std::str::FromStr;
33

44
/// Specifies which type of failures should cause a non-zero exit code.
55
///
6-
/// - `All`: Exit non-zero on any failure (program panics or invariant failures)
7-
/// - `Invariants`: Exit non-zero only on invariant/assert failures in fuzz tests
8-
/// - `Panics`: Exit non-zero only on program panics (program failed to complete)
6+
/// - `All`: Exit non-zero on any policy failure (program panics or custom invariant failures)
7+
/// - `Invariants`: Exit non-zero only on custom invariant failures in fuzz tests
98
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
109
pub enum ExitCodeMode {
11-
/// Exit non-zero on any failure (default behavior when exit code is enabled)
10+
/// Exit non-zero on any policy failure (default behavior when exit code is enabled)
1211
#[default]
1312
All,
14-
/// Exit non-zero only on invariant/assert failures in fuzz tests
13+
/// Exit non-zero only on custom invariant failures in fuzz tests
1514
Invariants,
16-
/// Exit non-zero only on program panics (program failed to complete)
17-
Panics,
1815
}
1916

2017
impl ExitCodeMode {
@@ -23,19 +20,13 @@ impl ExitCodeMode {
2320
match self {
2421
ExitCodeMode::All => "all",
2522
ExitCodeMode::Invariants => "invariants",
26-
ExitCodeMode::Panics => "panics",
2723
}
2824
}
2925

3026
/// Check if this mode should trigger exit code for invariant failures
3127
pub fn triggers_on_invariants(&self) -> bool {
3228
matches!(self, ExitCodeMode::All | ExitCodeMode::Invariants)
3329
}
34-
35-
/// Check if this mode should trigger exit code for program panics
36-
pub fn triggers_on_panics(&self) -> bool {
37-
matches!(self, ExitCodeMode::All | ExitCodeMode::Panics)
38-
}
3930
}
4031

4132
impl fmt::Display for ExitCodeMode {
@@ -51,9 +42,8 @@ impl FromStr for ExitCodeMode {
5142
match s.to_lowercase().as_str() {
5243
"all" => Ok(ExitCodeMode::All),
5344
"invariants" => Ok(ExitCodeMode::Invariants),
54-
"panics" => Ok(ExitCodeMode::Panics),
5545
_ => Err(format!(
56-
"Invalid exit code mode '{}'. Valid values are: all, invariants, panics",
46+
"Invalid exit code mode '{}'. Valid values are: all, invariants",
5747
s
5848
)),
5949
}
@@ -71,23 +61,13 @@ mod tests {
7161
ExitCodeMode::from_str("invariants").unwrap(),
7262
ExitCodeMode::Invariants
7363
);
74-
assert_eq!(
75-
ExitCodeMode::from_str("panics").unwrap(),
76-
ExitCodeMode::Panics
77-
);
7864
assert_eq!(ExitCodeMode::from_str("ALL").unwrap(), ExitCodeMode::All);
7965
assert!(ExitCodeMode::from_str("invalid").is_err());
8066
}
8167

8268
#[test]
8369
fn test_triggers() {
8470
assert!(ExitCodeMode::All.triggers_on_invariants());
85-
assert!(ExitCodeMode::All.triggers_on_panics());
86-
8771
assert!(ExitCodeMode::Invariants.triggers_on_invariants());
88-
assert!(!ExitCodeMode::Invariants.triggers_on_panics());
89-
90-
assert!(!ExitCodeMode::Panics.triggers_on_invariants());
91-
assert!(ExitCodeMode::Panics.triggers_on_panics());
9272
}
9373
}

0 commit comments

Comments
 (0)