use crate::descriptor::{NamespacedName, PopulationRef, RevisionBinding};
use crate::report::{ByteBudget, CaseBudget, TargetBinding};
use std::collections::BTreeSet;
use std::path::PathBuf;
#[path = "type_guard.rs"]
mod guard;
struct AbsolutePath(PathBuf);
pub const RUSTC_COVERAGE_TOOLCHAIN: &str = "1.98.1";
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct CoverageSourceRoot {
logical: NamespacedName,
checkout: PathBuf,
}
#[must_use = "a refusal is the reason a coverage source root was not built"]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CoverageSourceRootRefusal {
EmptyCheckout,
RelativeCheckout,
CheckoutTraversal,
NonUtf8Checkout,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct CoverageProfile {
name: NamespacedName,
version: u32,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct CoverageBudgets {
executions: CaseBudget,
input_bytes: ByteBudget,
export_bytes: u64,
points: u64,
retained_cases: CaseBudget,
retained_bytes: ByteBudget,
}
#[must_use = "a refusal is the reason coverage budgets were not built"]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CoverageBudgetRefusal {
Executions,
InputBytes,
ExportBytes,
Points,
RetainedCases,
RetainedBytes,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct CoverageCampaign {
population: PopulationRef,
revision: RevisionBinding,
profile: CoverageProfile,
budgets: CoverageBudgets,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct CoverageStanding {
campaign: CoverageCampaign,
target: TargetBinding,
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct CoverageSource {
root: NamespacedName,
relative: String,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum CoverageTool {
Profdata,
Cov,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum RustcCommand {
VerboseVersion,
Sysroot,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum RustcField {
Release,
Host,
LlvmVersion,
Sysroot,
}
#[must_use = "a refusal is the reason rustc coverage preflight was not ready"]
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum PreflightIncomplete {
TargetUnavailable {
path: PathBuf,
error: String,
},
TargetNotFile(PathBuf),
SourceRootUnavailable {
path: PathBuf,
error: String,
},
SourceRootNotDirectory(PathBuf),
SourceRootIdentity(CoverageSourceRootRefusal),
StartRustc {
command: RustcCommand,
error: String,
},
RustcFailed {
command: RustcCommand,
code: Option<i32>,
},
RustcOutputNotUtf8(RustcCommand),
MissingRustcField(RustcField),
RustcRelease {
required: &'static str,
observed: String,
},
RelativeRustcSysroot(PathBuf),
StartLlvmTool {
tool: CoverageTool,
path: PathBuf,
error: String,
},
LlvmToolFailed {
tool: CoverageTool,
code: Option<i32>,
},
LlvmToolOutputNotUtf8(CoverageTool),
MissingLlvmToolVersion(CoverageTool),
LlvmToolVersionsDiffer {
profdata: String,
cov: String,
},
RustcLlvmVersion {
rustc: String,
tools: String,
},
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct InterestingBytes {
bytes: Vec<u8>,
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum CoveragePoint {
Line {
source: CoverageSource,
line: u64,
},
Branch {
source: CoverageSource,
line: u64,
block: u64,
branch: u64,
},
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct CoverageObservation {
points: Vec<CoveragePoint>,
}
#[must_use = "a refusal is the reason a coverage export was not admitted"]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CoverageReadRefusal {
NonUtf8,
EmptySource {
record: usize,
},
RelativeSource {
record: usize,
},
SourceTraversal {
record: usize,
},
SourceOutsideRoot {
record: usize,
},
EmptyRelativeSource {
record: usize,
},
MissingSource {
record: usize,
},
MalformedLine {
record: usize,
},
MalformedBranch {
record: usize,
},
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct CoverageCorpus {
standing: CoverageStanding,
attempted_cases: u32,
attempted_input_bytes: u64,
observed: BTreeSet<CoveragePoint>,
interesting: Vec<InterestingBytes>,
retained_bytes: u64,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum CoverageAdmission {
Known,
Interesting(InterestingBytes),
}
#[must_use = "a refusal is the reason a coverage candidate was not judged"]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CoverageAdmissionRefusal {
CampaignMismatch,
Execution(FuzzExecution),
EmptyObservation,
PointBudgetExhausted {
bound: u64,
attempted: u64,
},
RetainedCaseBudgetExhausted {
bound: u32,
},
RetainedByteBudgetExhausted {
bound: u64,
attempted: u64,
},
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct MutationPlan {
budget: u32,
byte_limit: usize,
dictionary: Vec<Vec<u8>>,
}
#[must_use = "a refusal is the reason a mutation plan was not built"]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum MutationPlanRefusal {
ZeroBudget,
ZeroByteLimit,
EmptyDictionaryToken {
at: usize,
},
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum MutationKind {
BitFlip,
BoundarySubstitution,
Increment,
Decrement,
Delete,
InsertBoundary,
Duplicate,
Splice,
DictionaryInsert,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct MutationCandidate {
kind: MutationKind,
bytes: Vec<u8>,
}
#[must_use = "a refusal is the reason neighboring inputs were not produced"]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum MutationRefusal {
EmptySeed,
SeedExceedsByteLimit,
EmptyPartner,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub(crate) struct RustcCoverageTools {
profdata: PathBuf,
cov: PathBuf,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct InstrumentedTarget {
executable: PathBuf,
arguments: Vec<String>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct RustcProfileRequest {
rustc: PathBuf,
target: InstrumentedTarget,
source_root: CoverageSourceRoot,
scratch: PathBuf,
campaign: CoverageCampaign,
}
#[must_use = "a refusal is the reason a rustc coverage request was not built"]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum RustcProfileRequestRefusal {
Rustc,
RelativeRustc,
Target,
RelativeTarget,
Scratch,
RelativeScratch,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ReadyPreflight {
pub(super) request: RustcProfileRequest,
pub(super) tools: RustcCoverageTools,
pub(super) source_root: CoverageSourceRoot,
pub(super) standing: CoverageStanding,
pub(super) sysroot: PathBuf,
pub(super) release: String,
pub(super) host: String,
pub(super) llvm_version: String,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum FuzzExecution {
Success,
NonzeroExit(Option<i32>),
Crash(Option<i32>),
Timeout,
ResourceExhaustion,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct RustcProfileResult {
case: u32,
candidate: Vec<u8>,
execution: FuzzExecution,
observation: CoverageObservation,
standing: CoverageStanding,
}
#[must_use = "a refusal is the reason a rustc coverage execution did not complete"]
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum RustcProfileRefusal {
EmptyCandidate,
CampaignMismatch,
CaseBudgetExhausted {
bound: u32,
},
InputBudgetExhausted {
bound: u64,
attempted: u64,
},
CaseAlreadyExists(PathBuf),
CreateCase(String),
StartTarget(String),
WriteCandidate(String),
OpenCandidate(String),
SuperviseTarget(String),
SupervisorReturnedBeforeExit,
InspectTarget(String),
CleanupTarget {
after: Box<RustcProfileRefusal>,
cleanup: String,
},
MissingProfile,
StartProfdata(String),
ProfdataFailed(Option<i32>),
StartCov(String),
CovOutputBudgetExhausted {
bound: u64,
observed_at_least: u64,
},
ReadCov(String),
WaitCov(String),
CovFailed(Option<i32>),
CleanupCov {
after: Box<RustcProfileRefusal>,
cleanup: String,
},
Coverage(CoverageReadRefusal),
CleanupCase {
after: Option<Box<RustcProfileRefusal>>,
cleanup: String,
},
}
#[must_use = "a refusal is the reason fuzz compose did not mint a replay capsule"]
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ComposeRefusal {
Reduction(crate::generate::ReductionRefusal),
ReplayFingerprintMoved,
ReplayNoFailure,
}