Structure-aware feedback-guided fuzzing toolkit for MoonBit
///|
let builder = @grammata.GrammarBuilder::new()
///|
let digit = builder.ascii_range('0', '9')
///|
let document = builder.repeat(digit, minimum=1, maximum=16)
///|
let grammar = builder.set_start(document).build().unwrap()
///|
let tree = grammar.generate(seed=42L).unwrap()pub(all) enum AdmissionDecision {
Admitted(Int, AdmissionReason)
Rejected(RejectionReason)
} derive(Eq, Debug)pub(all) enum AdmissionReason {
FirstInput
NovelFeature(Int)
NovelSignature
NewFailure(FailureFingerprint)
} derive(Eq, Debug)pub(all) struct CampaignConfig {
seed : Int64
executions : Int
initial_inputs : Int
crossover_percent : Int
generation_budget : GenerationBudget
mutation_config : MutationConfig
crossover_config : CrossoverConfig
corpus_limits : CorpusLimits
max_events : Int
} derive(Eq, Debug)pub(all) enum CampaignError {
InvalidCampaignConfig(String)
InitialGenerationFailed(GenerationError)
CorpusCouldNotBeSeeded
} derive(Eq, Debug)pub(all) struct CampaignEvent {
execution : Int
input_bytes : Int
corpus_entries : Int
kind : CampaignEventKind
} derive(Eq, Debug)pub(all) enum CampaignEventKind {
Generated
Mutated(MutationStrategy)
Crossed
Admitted(AdmissionReason)
RejectedInput(RejectionReason)
FailureFound(FailureFingerprint)
MutationSkipped
} derive(Eq, Debug)pub(all) struct CampaignResult {
statistics : CampaignStatistics
corpus : Array[CorpusEntry]
failures : Array[ReplayRecord]
events : Array[CampaignEvent]
} derive(Eq, Debug)pub(all) struct CampaignStatistics {
requested_executions : Int
completed_executions : Int
generated_inputs : Int
mutated_inputs : Int
crossed_inputs : Int
admitted_inputs : Int
rejected_inputs : Int
unique_failures : Int
mutation_failures : Int
final_corpus : CorpusStatistics
} derive(Eq, Debug)pub struct Corpus {
entries : Array[CorpusEntry]
limits : CorpusLimits
registry : FeatureRegistry
input_ids : HashMap[String, Int]
failure_ids : HashMap[FailureFingerprint, Int]
total_bytes : Int
failure_count : Int
}fn Corpus::consider(self : Corpus, tree : DerivationTree, observation : TargetObservation, origin : CorpusOrigin) -> AdmissionDecisionpub(all) struct CorpusEntry {
id : Int
tree : DerivationTree
observation : TargetObservation
signature : FeedbackSignature
failure : FailureFingerprint?
origin : CorpusOrigin
input_key : String
executions : Int
selections : Int
discoveries : Int
energy : Int
} derive(Eq, Debug)pub(all) struct CrossoverResult {
tree : DerivationTree
recipient_node : Int
donor_node : Int
rule : RuleId
} derive(Eq, Debug)pub(all) struct DerivationTree {
node_id : Int
rule : RuleId
kind : DerivationKind
payload : Array[Byte]
children : Array[DerivationTree]
} derive(Eq, Debug)fn DerivationTree::branch(node_id : Int, rule : RuleId, kind : DerivationKind, children : Array[DerivationTree]) -> DerivationTreefn DerivationTree::leaf(node_id : Int, rule : RuleId, kind : DerivationKind, payload : Array[Byte]) -> DerivationTreefn DerivationTree::replace(self : DerivationTree, node_id : Int, replacement : DerivationTree) -> DerivationTreepub struct FeatureRegistry {
seen : HashMap[Feature, Int]
signatures : HashMap[FeedbackSignature, Int]
observations : Int
}fn FeatureRegistry::observe(self : FeatureRegistry, observation : TargetObservation) -> FeatureDeltafn GenerationBudget::new(max_depth? : Int, max_nodes? : Int, max_bytes? : Int, max_repeat? : Int) -> GenerationBudgetpub(all) enum GenerationError {
InvalidBudget(String)
UnproductiveGrammar(AnalysisError)
DepthBudgetExceeded(Int)
NodeBudgetExceeded(Int)
ByteBudgetExceeded(Int)
NoViableAlternative(Int)
InvalidGeneratedInteger(Int, Int)
} derive(Eq, Debug)fn Grammar::generate(self : Grammar, seed~ : Int64, budget? : GenerationBudget) -> Result[DerivationTree, GenerationError]fn Grammar::generate_from(self : Grammar, rule : RuleId, seed~ : Int64, budget? : GenerationBudget) -> Result[DerivationTree, GenerationError]fn Grammar::mutate(self : Grammar, tree : DerivationTree, seed~ : Int64, config? : MutationConfig) -> Result[MutationResult, MutationError]fn Grammar::mutate_with(self : Grammar, tree : DerivationTree, strategy : MutationStrategy, seed~ : Int64, config? : MutationConfig) -> Result[MutationResult, MutationError]fn Grammar::reduce_failure(self : Grammar, tree : DerivationTree, target : Target, fingerprint? : FailureFingerprint, seed? : Int64, config? : ReductionConfig) -> Result[ReductionResult, ReductionError]pub(all) struct GrammarAnalysis {
rules : Array[RuleProperties]
reachable_count : Int
unreachable_count : Int
recursive_count : Int
nullable_count : Int
productive_count : Int
} derive(Eq, Debug)fn GrammarBuilder::ascii_range(self : GrammarBuilder, first : Char, last : Char, name? : String) -> RuleIdfn GrammarBuilder::choice(self : GrammarBuilder, alternatives : Array[Alternative], name? : String) -> RuleIdfn GrammarBuilder::dictionary(self : GrammarBuilder, values : Array[String], name? : String) -> RuleIdfn GrammarBuilder::integer(self : GrammarBuilder, minimum : Int, maximum : Int, name? : String) -> RuleIdfn GrammarBuilder::optional(self : GrammarBuilder, child : RuleId, present_weight? : Int, name? : String) -> RuleIdfn GrammarBuilder::repeat(self : GrammarBuilder, child : RuleId, minimum? : Int, maximum? : Int, name? : String) -> RuleIdfn GrammarBuilder::sequence(self : GrammarBuilder, children : Array[RuleId], name? : String) -> RuleIdpub(all) enum GrammarError {
EmptyGrammar
InvalidStartRule(Int)
InvalidRuleReference(Int, Int)
MissingNamedRule(String)
DuplicateRuleName(String)
EmptyByteSet(Int)
InvalidByteValue(Int, Int)
EmptyDictionary(Int)
EmptyChoice(Int)
NonPositiveWeight(Int, Int)
InvalidRepeatBounds(Int, Int, Int)
InvalidIntegerBounds(Int, Int, Int)
InvalidOptionalWeight(Int, Int)
} derive(Eq, Debug)pub struct MetamorphicTransform {
name : String
apply : (Bytes) -> Bytes
relation : (TargetObservation, TargetObservation) -> Bool
}fn MetamorphicTransform::new(name : String, apply : (Bytes) -> Bytes, relation : (TargetObservation, TargetObservation) -> Bool) -> MetamorphicTransformpub(all) struct MutationConfig {
budget : GenerationBudget
attempts : Int
maximum_output_bytes : Int
} derive(Eq, Debug)pub(all) enum MutationError {
EmptyTree
NoApplicableMutation
GenerationFailed(GenerationError)
OutputBudgetExceeded(Int)
} derive(Eq, Debug)pub(all) struct MutationResult {
tree : DerivationTree
strategy : MutationStrategy
changed_node : Int
detail : String
} derive(Eq, Debug)pub(all) struct Random {
state : Int64
initial_seed : Int64
draws : Int
}pub(all) struct ReductionConfig {
max_attempts : Int
generation_trials : Int
generation_budget : GenerationBudget
} derive(Eq, Debug)pub(all) enum ReductionError {
InputDoesNotFail
FingerprintMismatch(FailureFingerprint, FailureFingerprint)
NoReductionPossible
} derive(Eq, Debug)pub(all) struct ReductionResult {
original : DerivationTree
reduced : DerivationTree
fingerprint : FailureFingerprint
attempts : Int
accepted_steps : Array[ReductionStep]
} derive(Eq, Debug)pub(all) struct ReductionStep {
kind : ReductionKind
node_id : Int
before_bytes : Int
after_bytes : Int
before_nodes : Int
after_nodes : Int
} derive(Eq, Debug)pub(all) struct ReplayOutcome {
observation : TargetObservation
feedback_matches : Bool
failure_matches : Bool
result_matches : Bool
} derive(Eq, Debug)pub(all) struct ReplayRecord {
schema_version : Int
target_name : String
seed : Int64
input : Bytes
feedback_signature : FeedbackSignature
failure_fingerprint : FailureFingerprint?
result_digest : String?
generation_budget : GenerationBudget
} derive(Eq, Debug)fn ReplayRecord::decode_json(text : String, max_input_bytes? : Int, max_artifact_bytes? : Int) -> Result[ReplayRecord, ReplayError]fn ReplayRecord::new(target_name~ : String, seed~ : Int64, input~ : Bytes, observation~ : TargetObservation, generation_budget? : GenerationBudget) -> ReplayRecordpub(all) struct TargetObservation {
disposition : ExecutionDisposition
features : Array[Feature]
result_digest : String?
cost_class : Int
} derive(Eq, Debug)fn accepted(features? : Array[Feature], result_digest? : String, cost_class? : Int) -> TargetObservationfn crossover(recipient : DerivationTree, donor : DerivationTree, seed~ : Int64, config? : CrossoverConfig) -> Result[CrossoverResult, CrossoverError]fn differential_target(name : String, left : Target, right : Target, policy? : DifferentialPolicy) -> Targetfn metamorphic_target(name : String, base : Target, transforms : Array[MetamorphicTransform]) -> Targetfn observation(disposition : ExecutionDisposition, features? : Array[Feature], result_digest? : String, cost_class? : Int) -> TargetObservationfn run_campaign(grammar : Grammar, target : Target, config : CampaignConfig) -> Result[CampaignResult, CampaignError]Install
Download zipStructure-aware feedback-guided fuzzing toolkit for MoonBit