///|
fn operation_grammar() -> @grammata.Grammar {
let builder = @grammata.GrammarBuilder::new()
let operation = builder.dictionary(["A", "U", "F", "R"], name="operation")
let sequence = builder.repeat(
operation,
minimum=1,
maximum=20,
name="operation-sequence",
)
builder.set_start(sequence).build().unwrap()
}
///|
enum ResourceState {
Empty
Live
Freed
} derive(Debug, Eq)
///|
fn state_name(state : ResourceState) -> String {
match state {
Empty => "empty"
Live => "live"
Freed => "freed"
}
}
///|
fn operation_target() -> @grammata.Target {
@grammata.Target::new("state-sequence-demo", input => {
let mut state = Empty
let features : Array[@grammata.Feature] = [
@grammata.feature("initial-state", "empty"),
]
for index, byte in input {
let operation = byte.to_int().unsafe_to_char()
let before = state_name(state)
match operation {
'A' => {
if state == Live {
return @grammata.rejected("double-allocate", features~)
}
state = Live
}
'U' => {
if state == Freed {
features.push(@grammata.feature("transition", "freed->use"))
return @grammata.failed(
"lifecycle",
"use-after-free@" + index.to_string(),
features~,
)
}
if state == Empty {
return @grammata.rejected("use-before-allocate", features~)
}
}
'F' => {
if state != Live {
return @grammata.rejected("free-non-live", features~)
}
state = Freed
}
'R' => state = Empty
_ => return @grammata.rejected("unknown-operation", features~)
}
features.push(
@grammata.feature(
"transition",
before + "-" + operation.to_string() + "->" + state_name(state),
),
)
}
@grammata.accepted(
features~,
result_digest=state_name(state),
cost_class=input.length() / 4,
)
})
}
///|
fn run_state_sequence_demo(executions : Int) -> @grammata.CampaignResult {
let config : @grammata.CampaignConfig = {
..@grammata.CampaignConfig::default(seed=40404L),
executions,
initial_inputs: executions.min(16),
crossover_percent: 25,
}
@grammata.run_campaign(operation_grammar(), operation_target(), config).unwrap()
}
///|
fn main {
let result = run_state_sequence_demo(1000)
println(result.markdown_report(title="State Operation Sequence Fuzzing Demo"))
if !result.failures.is_empty() {
println("First replay artifact:")
println(result.failures[0].encode_json())
}
}