remove unused code
This commit is contained in:
parent
6cb2be4408
commit
acf9b04e70
@ -1,41 +1,22 @@
|
|||||||
use hashbrown::{hash_map::Entry, HashMap};
|
use libafl_bolts::Named;
|
||||||
use libafl_bolts::{
|
|
||||||
current_nanos,
|
|
||||||
rands::StdRand,
|
|
||||||
tuples::{tuple_list,MatchName},
|
|
||||||
impl_serdeany,
|
|
||||||
Named,
|
|
||||||
};
|
|
||||||
use libafl::{
|
use libafl::{
|
||||||
executors::{ExitKind},
|
executors::ExitKind,
|
||||||
fuzzer::{StdFuzzer},
|
observers::Observer,
|
||||||
inputs::{BytesInput, HasTargetBytes},
|
|
||||||
observers::{Observer,VariableMapObserver},
|
|
||||||
state::{StdState},
|
|
||||||
Error,
|
Error,
|
||||||
common::HasNamedMetadata,
|
common::HasNamedMetadata,
|
||||||
observers::ObserversTuple, prelude::UsesInput,
|
observers::ObserversTuple, prelude::UsesInput,
|
||||||
};
|
};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::{cell::UnsafeCell, cmp::max, env, fs::OpenOptions, io::Write, time::Instant};
|
use std::{fs::OpenOptions, io::Write};
|
||||||
|
|
||||||
use libafl_qemu::{
|
|
||||||
emu,
|
|
||||||
emu::Emulator,
|
|
||||||
executor::QemuExecutor,
|
|
||||||
helpers::{QemuHelper, QemuHelperTuple, HasInstrumentationFilter},
|
|
||||||
};
|
|
||||||
use libafl::events::EventFirer;
|
use libafl::events::EventFirer;
|
||||||
use libafl::state::MaybeHasClientPerfMonitor;
|
use libafl::state::MaybeHasClientPerfMonitor;
|
||||||
use libafl::prelude::State;
|
use libafl::prelude::State;
|
||||||
use libafl::inputs::Input;
|
|
||||||
use libafl::feedbacks::Feedback;
|
use libafl::feedbacks::Feedback;
|
||||||
use libafl::SerdeAny;
|
use libafl::SerdeAny;
|
||||||
use libafl::common::HasMetadata;
|
use libafl::common::HasMetadata;
|
||||||
use libafl::corpus::testcase::Testcase;
|
use libafl::corpus::testcase::Testcase;
|
||||||
use core::{fmt::Debug, time::Duration};
|
use core::{fmt::Debug, time::Duration};
|
||||||
// use libafl::feedbacks::FeedbackState;
|
|
||||||
// use libafl::state::HasFeedbackStates;
|
|
||||||
use std::time::{SystemTime, UNIX_EPOCH};
|
use std::time::{SystemTime, UNIX_EPOCH};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
@ -45,12 +26,12 @@ pub static mut FUZZ_START_TIMESTAMP : SystemTime = UNIX_EPOCH;
|
|||||||
pub const QEMU_ICOUNT_SHIFT : u32 = 5;
|
pub const QEMU_ICOUNT_SHIFT : u32 = 5;
|
||||||
pub const QEMU_ISNS_PER_SEC : u32 = u32::pow(10, 9) / u32::pow(2, QEMU_ICOUNT_SHIFT);
|
pub const QEMU_ISNS_PER_SEC : u32 = u32::pow(10, 9) / u32::pow(2, QEMU_ICOUNT_SHIFT);
|
||||||
pub const QEMU_ISNS_PER_USEC : u32 = QEMU_ISNS_PER_SEC / 1000000;
|
pub const QEMU_ISNS_PER_USEC : u32 = QEMU_ISNS_PER_SEC / 1000000;
|
||||||
pub const QEMU_NS_PER_ISN : u32 = 1 << QEMU_ICOUNT_SHIFT;
|
pub const _QEMU_NS_PER_ISN : u32 = 1 << QEMU_ICOUNT_SHIFT;
|
||||||
pub const TARGET_SYSCLK_FREQ : u32 = 25 * 1000 * 1000;
|
pub const _TARGET_SYSCLK_FREQ : u32 = 25 * 1000 * 1000;
|
||||||
pub const TARGET_MHZ_PER_MIPS : f32 = TARGET_SYSCLK_FREQ as f32 / QEMU_ISNS_PER_SEC as f32;
|
pub const _TARGET_MHZ_PER_MIPS : f32 = _TARGET_SYSCLK_FREQ as f32 / QEMU_ISNS_PER_SEC as f32;
|
||||||
pub const TARGET_MIPS_PER_MHZ : f32 = QEMU_ISNS_PER_SEC as f32 / TARGET_SYSCLK_FREQ as f32;
|
pub const _TARGET_MIPS_PER_MHZ : f32 = QEMU_ISNS_PER_SEC as f32 / _TARGET_SYSCLK_FREQ as f32;
|
||||||
pub const TARGET_SYSCLK_PER_QEMU_SEC : u32 = (TARGET_SYSCLK_FREQ as f32 * TARGET_MIPS_PER_MHZ) as u32;
|
pub const _TARGET_SYSCLK_PER_QEMU_SEC : u32 = (_TARGET_SYSCLK_FREQ as f32 * _TARGET_MIPS_PER_MHZ) as u32;
|
||||||
pub const QEMU_SYSCLK_PER_TARGET_SEC : u32 = (TARGET_SYSCLK_FREQ as f32 * TARGET_MHZ_PER_MIPS) as u32;
|
pub const _QEMU_SYSCLK_PER_TARGET_SEC : u32 = (_TARGET_SYSCLK_FREQ as f32 * _TARGET_MHZ_PER_MIPS) as u32;
|
||||||
|
|
||||||
//========== Metadata
|
//========== Metadata
|
||||||
#[derive(Debug, SerdeAny, Serialize, Deserialize)]
|
#[derive(Debug, SerdeAny, Serialize, Deserialize)]
|
||||||
@ -244,7 +225,7 @@ where
|
|||||||
&mut self,
|
&mut self,
|
||||||
_state: &mut S,
|
_state: &mut S,
|
||||||
_manager: &mut EM,
|
_manager: &mut EM,
|
||||||
observers: &OT,
|
_observers: &OT,
|
||||||
testcase: &mut Testcase<S::Input>,
|
testcase: &mut Testcase<S::Input>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
*testcase.exec_time_mut() = self.exec_time;
|
*testcase.exec_time_mut() = self.exec_time;
|
||||||
@ -325,7 +306,7 @@ where
|
|||||||
|
|
||||||
/// Append to the testcase the generated metadata in case of a new corpus item
|
/// Append to the testcase the generated metadata in case of a new corpus item
|
||||||
#[inline]
|
#[inline]
|
||||||
fn append_metadata<EM, OT>(&mut self, _state: &mut S, _manager: &mut EM, observers: &OT, testcase: &mut Testcase<S::Input>) -> Result<(), Error> {
|
fn append_metadata<EM, OT>(&mut self, _state: &mut S, _manager: &mut EM, _observers: &OT, _testcase: &mut Testcase<S::Input>) -> Result<(), Error> {
|
||||||
// testcase.metadata_mut().insert(QemuIcountMetadata{runtime: self.last_runtime});
|
// testcase.metadata_mut().insert(QemuIcountMetadata{runtime: self.last_runtime});
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@ use libafl_bolts::{
|
|||||||
core_affinity::Cores, current_nanos, rands::StdRand, shmem::{ShMemProvider, StdShMemProvider}, tuples::tuple_list, AsSlice
|
core_affinity::Cores, current_nanos, rands::StdRand, shmem::{ShMemProvider, StdShMemProvider}, tuples::tuple_list, AsSlice
|
||||||
};
|
};
|
||||||
use libafl::{
|
use libafl::{
|
||||||
common::{HasMetadata, HasNamedMetadata}, corpus::{Corpus, InMemoryCorpus, OnDiskCorpus}, events::{launcher::Launcher, EventConfig}, executors::ExitKind, feedback_or, feedback_or_fast, feedbacks::{CrashFeedback, MaxMapFeedback, TimeoutFeedback}, fuzzer::{Fuzzer, StdFuzzer}, inputs::{BytesInput, HasTargetBytes}, monitors::MultiMonitor, observers::{CanTrack, VariableMapObserver}, prelude::{havoc_mutations, minimizer::TopRatedsMetadata, CorpusId, Generator, HitcountsMapObserver, RandBytesGenerator, SimpleEventManager, SimpleMonitor, SimpleRestartingEventManager, StdScheduledMutator}, schedulers::{IndexesLenTimeMinimizerScheduler, QueueScheduler}, stages::StdMutationalStage, state::{HasCorpus, StdState}, Error, Evaluator
|
common::{HasMetadata, HasNamedMetadata}, corpus::{Corpus, InMemoryCorpus, OnDiskCorpus}, events::{launcher::Launcher, EventConfig}, executors::ExitKind, feedback_or, feedback_or_fast, feedbacks::{CrashFeedback, MaxMapFeedback, TimeoutFeedback}, fuzzer::{Fuzzer, StdFuzzer}, inputs::{BytesInput, HasTargetBytes}, monitors::MultiMonitor, observers::{CanTrack, VariableMapObserver}, prelude::{havoc_mutations, minimizer::TopRatedsMetadata, CorpusId, Generator, HitcountsMapObserver, RandBytesGenerator, SimpleEventManager, SimpleMonitor, SimpleRestartingEventManager, StdScheduledMutator}, schedulers::QueueScheduler, stages::StdMutationalStage, state::{HasCorpus, StdState}, Error, Evaluator
|
||||||
};
|
};
|
||||||
use libafl_qemu::{
|
use libafl_qemu::{
|
||||||
edges::{self, edges_map_mut_ptr, QemuEdgeCoverageHelper, MAX_EDGES_FOUND}, elf::EasyElf, emu::Emulator, GuestAddr, GuestPhysAddr, QemuExecutor, QemuFilterList, QemuHooks, Regs, StdInstrumentationFilter
|
edges::{self, edges_map_mut_ptr, QemuEdgeCoverageHelper, MAX_EDGES_FOUND}, elf::EasyElf, emu::Emulator, GuestAddr, GuestPhysAddr, QemuExecutor, QemuFilterList, QemuHooks, Regs, StdInstrumentationFilter
|
||||||
@ -780,7 +780,7 @@ let mut run_client = |state: Option<_>, mut mgr, _core_id| {
|
|||||||
#[cfg(feature = "restarting")]
|
#[cfg(feature = "restarting")]
|
||||||
{
|
{
|
||||||
let mut shmem_provider = StdShMemProvider::new().unwrap();
|
let mut shmem_provider = StdShMemProvider::new().unwrap();
|
||||||
let (state, mut mgr) = match SimpleRestartingEventManager::launch(monitor, &mut shmem_provider)
|
let (state, mgr) = match SimpleRestartingEventManager::launch(monitor, &mut shmem_provider)
|
||||||
{
|
{
|
||||||
// The restarting state will spawn the same process again as child, then restarted it each time it crashes.
|
// The restarting state will spawn the same process again as child, then restarted it each time it crashes.
|
||||||
Ok(res) => res,
|
Ok(res) => res,
|
||||||
|
@ -1,12 +1,9 @@
|
|||||||
use libafl::SerdeAny;
|
use libafl::SerdeAny;
|
||||||
use libafl_bolts::ownedref::OwnedSlice;
|
|
||||||
use libafl::inputs::BytesInput;
|
|
||||||
use libafl::prelude::UsesInput;
|
use libafl::prelude::UsesInput;
|
||||||
use libafl::common::HasNamedMetadata;
|
use libafl::common::HasNamedMetadata;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use crate::clock::QemuClockObserver;
|
use crate::clock::QemuClockObserver;
|
||||||
use libafl::corpus::Testcase;
|
use libafl::corpus::Testcase;
|
||||||
use libafl_bolts::tuples::MatchName;
|
|
||||||
use std::collections::hash_map::DefaultHasher;
|
use std::collections::hash_map::DefaultHasher;
|
||||||
use std::hash::Hasher;
|
use std::hash::Hasher;
|
||||||
use std::hash::Hash;
|
use std::hash::Hash;
|
||||||
@ -17,17 +14,13 @@ use libafl::feedbacks::Feedback;
|
|||||||
use libafl_bolts::Named;
|
use libafl_bolts::Named;
|
||||||
use libafl::Error;
|
use libafl::Error;
|
||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
use libafl::{executors::ExitKind, inputs::Input, observers::ObserversTuple, common::HasMetadata};
|
use libafl::{executors::ExitKind, observers::ObserversTuple, common::HasMetadata};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use super::ExecInterval;
|
use super::ExecInterval;
|
||||||
use super::ReducedFreeRTOSSystemState;
|
use super::ReducedFreeRTOSSystemState;
|
||||||
use super::FreeRTOSSystemStateMetadata;
|
use super::FreeRTOSSystemStateMetadata;
|
||||||
use super::observers::QemuSystemStateObserver;
|
use super::observers::QemuSystemStateObserver;
|
||||||
use petgraph::prelude::DiGraph;
|
|
||||||
use petgraph::graph::NodeIndex;
|
|
||||||
use petgraph::Direction;
|
|
||||||
use std::cmp::Ordering;
|
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
|
||||||
//============================= Feedback
|
//============================= Feedback
|
||||||
@ -71,10 +64,10 @@ where
|
|||||||
fn is_interesting<EM, OT>(
|
fn is_interesting<EM, OT>(
|
||||||
&mut self,
|
&mut self,
|
||||||
state: &mut S,
|
state: &mut S,
|
||||||
manager: &mut EM,
|
_manager: &mut EM,
|
||||||
input: &S::Input,
|
_input: &S::Input,
|
||||||
observers: &OT,
|
observers: &OT,
|
||||||
exit_kind: &ExitKind,
|
_exit_kind: &ExitKind,
|
||||||
) -> Result<bool, Error>
|
) -> Result<bool, Error>
|
||||||
where
|
where
|
||||||
EM: EventFirer<State = S>,
|
EM: EventFirer<State = S>,
|
||||||
@ -127,7 +120,7 @@ where
|
|||||||
|
|
||||||
/// Append to the testcase the generated metadata in case of a new corpus item
|
/// Append to the testcase the generated metadata in case of a new corpus item
|
||||||
#[inline]
|
#[inline]
|
||||||
fn append_metadata<EM, OT>(&mut self, _state: &mut S, _manager: &mut EM, observers: &OT, testcase: &mut Testcase<S::Input>) -> Result<(), Error> {
|
fn append_metadata<EM, OT>(&mut self, _state: &mut S, _manager: &mut EM, _observers: &OT, testcase: &mut Testcase<S::Input>) -> Result<(), Error> {
|
||||||
let a = self.last_trace.take();
|
let a = self.last_trace.take();
|
||||||
match a {
|
match a {
|
||||||
Some(s) => testcase.metadata_map_mut().insert(FreeRTOSSystemStateMetadata::new(s)),
|
Some(s) => testcase.metadata_map_mut().insert(FreeRTOSSystemStateMetadata::new(s)),
|
||||||
@ -177,11 +170,11 @@ where
|
|||||||
{
|
{
|
||||||
fn is_interesting<EM, OT>(
|
fn is_interesting<EM, OT>(
|
||||||
&mut self,
|
&mut self,
|
||||||
state: &mut S,
|
_state: &mut S,
|
||||||
manager: &mut EM,
|
_manager: &mut EM,
|
||||||
input: &S::Input,
|
_input: &S::Input,
|
||||||
observers: &OT,
|
observers: &OT,
|
||||||
exit_kind: &ExitKind,
|
_exit_kind: &ExitKind,
|
||||||
) -> Result<bool, Error>
|
) -> Result<bool, Error>
|
||||||
where
|
where
|
||||||
EM: EventFirer<State = S>,
|
EM: EventFirer<State = S>,
|
||||||
@ -203,7 +196,7 @@ where
|
|||||||
}
|
}
|
||||||
/// Append to the testcase the generated metadata in case of a new corpus item
|
/// Append to the testcase the generated metadata in case of a new corpus item
|
||||||
#[inline]
|
#[inline]
|
||||||
fn append_metadata<EM, OT>(&mut self, _state: &mut S, _manager: &mut EM, observers: &OT, testcase: &mut Testcase<S::Input>) -> Result<(), Error> {
|
fn append_metadata<EM, OT>(&mut self, _state: &mut S, _manager: &mut EM, _observers: &OT, _testcase: &mut Testcase<S::Input>) -> Result<(), Error> {
|
||||||
if !self.dump_metadata {return Ok(());}
|
if !self.dump_metadata {return Ok(());}
|
||||||
// let a = self.last_trace.take();
|
// let a = self.last_trace.take();
|
||||||
// match a {
|
// match a {
|
||||||
@ -232,13 +225,15 @@ impl Named for DumpSystraceFeedback
|
|||||||
impl DumpSystraceFeedback
|
impl DumpSystraceFeedback
|
||||||
{
|
{
|
||||||
/// Creates a new [`DumpSystraceFeedback`]
|
/// Creates a new [`DumpSystraceFeedback`]
|
||||||
#[must_use]
|
#[allow(unused)]
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {name: Cow::from("Dumpsystemstate".to_string()), dumpfile: None, dump_metadata: false, last_trace: None, last_states: None }
|
Self {name: Cow::from("Dumpsystemstate".to_string()), dumpfile: None, dump_metadata: false, last_trace: None, last_states: None }
|
||||||
}
|
}
|
||||||
|
#[allow(unused)]
|
||||||
pub fn with_dump(dumpfile: Option<PathBuf>) -> Self {
|
pub fn with_dump(dumpfile: Option<PathBuf>) -> Self {
|
||||||
Self {name: Cow::from("Dumpsystemstate".to_string()), dumpfile: dumpfile, dump_metadata: false, last_trace: None, last_states: None}
|
Self {name: Cow::from("Dumpsystemstate".to_string()), dumpfile: dumpfile, dump_metadata: false, last_trace: None, last_states: None}
|
||||||
}
|
}
|
||||||
|
#[allow(unused)]
|
||||||
pub fn metadata_only() -> Self {
|
pub fn metadata_only() -> Self {
|
||||||
Self {name: Cow::from("Dumpsystemstate".to_string()), dumpfile: None, dump_metadata: true, last_trace: None, last_states: None}
|
Self {name: Cow::from("Dumpsystemstate".to_string()), dumpfile: None, dump_metadata: true, last_trace: None, last_states: None}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
#![allow(non_camel_case_types,non_snake_case,non_upper_case_globals,deref_nullptr)]
|
#![allow(non_camel_case_types,non_snake_case,non_upper_case_globals,deref_nullptr,unused)]
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
// Manual Types
|
// Manual Types
|
||||||
use libafl_qemu::{Emulator, Qemu};
|
use libafl_qemu::Qemu;
|
||||||
|
|
||||||
/*========== Start of generated Code =============*/
|
/*========== Start of generated Code =============*/
|
||||||
pub type char_ptr = ::std::os::raw::c_uint;
|
pub type char_ptr = ::std::os::raw::c_uint;
|
||||||
|
@ -1,632 +0,0 @@
|
|||||||
|
|
||||||
use libafl::SerdeAny;
|
|
||||||
/// Feedbacks organizing SystemStates as a graph
|
|
||||||
// use libafl::inputs::HasBytesVec;
|
|
||||||
use libafl_bolts::rands::random_seed;
|
|
||||||
use libafl_bolts::rands::StdRand;
|
|
||||||
use libafl::mutators::Mutator;
|
|
||||||
use libafl::mutators::MutationResult;
|
|
||||||
use libafl::prelude::HasTargetBytes;
|
|
||||||
use libafl::prelude::UsesInput;
|
|
||||||
use libafl::common::HasNamedMetadata;
|
|
||||||
use libafl::state::UsesState;
|
|
||||||
use libafl::prelude::State;
|
|
||||||
use core::marker::PhantomData;
|
|
||||||
use libafl::state::HasCorpus;
|
|
||||||
use libafl::state::HasSolutions;
|
|
||||||
use libafl::state::HasRand;
|
|
||||||
use crate::worst::MaxExecsLenFavFactor;
|
|
||||||
use crate::worst::MaxTimeFavFactor;
|
|
||||||
use libafl::schedulers::MinimizerScheduler;
|
|
||||||
use libafl_bolts::HasRefCnt;
|
|
||||||
use libafl_bolts::AsSlice;
|
|
||||||
use libafl_bolts::ownedref::OwnedSlice;
|
|
||||||
use libafl::inputs::BytesInput;
|
|
||||||
use std::path::PathBuf;
|
|
||||||
use crate::clock::QemuClockObserver;
|
|
||||||
use libafl::corpus::Testcase;
|
|
||||||
use libafl_bolts::tuples::MatchName;
|
|
||||||
use std::collections::hash_map::DefaultHasher;
|
|
||||||
use std::hash::Hasher;
|
|
||||||
use std::hash::Hash;
|
|
||||||
use libafl::events::EventFirer;
|
|
||||||
use libafl::state::MaybeHasClientPerfMonitor;
|
|
||||||
use libafl::feedbacks::Feedback;
|
|
||||||
use libafl_bolts::Named;
|
|
||||||
use libafl::Error;
|
|
||||||
use hashbrown::HashMap;
|
|
||||||
use libafl::{executors::ExitKind, inputs::Input, observers::ObserversTuple, common::HasMetadata};
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
use super::ExecInterval;
|
|
||||||
use super::ReducedFreeRTOSSystemState;
|
|
||||||
use super::FreeRTOSSystemStateMetadata;
|
|
||||||
use super::observers::QemuSystemStateObserver;
|
|
||||||
use petgraph::prelude::DiGraph;
|
|
||||||
use petgraph::graph::NodeIndex;
|
|
||||||
use petgraph::Direction;
|
|
||||||
use std::cmp::Ordering;
|
|
||||||
use std::borrow::Cow;
|
|
||||||
|
|
||||||
use libafl_bolts::rands::Rand;
|
|
||||||
|
|
||||||
//============================= Data Structures
|
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Default)]
|
|
||||||
pub struct VariantTuple
|
|
||||||
{
|
|
||||||
pub start_tick: u64,
|
|
||||||
pub end_tick: u64,
|
|
||||||
input_counter: u32,
|
|
||||||
pub input: Vec<u8>, // in the end any kind of input are bytes, regardless of type and lifetime
|
|
||||||
}
|
|
||||||
impl VariantTuple {
|
|
||||||
fn from(other: &ReducedFreeRTOSSystemState,input: Vec<u8>) -> Self {
|
|
||||||
// VariantTuple{
|
|
||||||
// start_tick: other.tick,
|
|
||||||
// end_tick: other.end_tick,
|
|
||||||
// input_counter: other.input_counter,
|
|
||||||
// input: input,
|
|
||||||
// }
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug, Default)]
|
|
||||||
pub struct SysGraphNode
|
|
||||||
{
|
|
||||||
base: ReducedFreeRTOSSystemState,
|
|
||||||
pub variants: Vec<VariantTuple>,
|
|
||||||
}
|
|
||||||
impl SysGraphNode {
|
|
||||||
fn from(base: ReducedFreeRTOSSystemState, input: Vec<u8>) -> Self {
|
|
||||||
SysGraphNode{variants: vec![VariantTuple::from(&base, input)], base:base }
|
|
||||||
}
|
|
||||||
/// unites the variants of this value with another, draining the other if the bases are equal
|
|
||||||
fn unite(&mut self, other: &mut SysGraphNode) -> bool {
|
|
||||||
if self!=other {return false;}
|
|
||||||
self.variants.append(&mut other.variants);
|
|
||||||
self.variants.dedup();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
/// add a Varint from a [`RefinedFreeRTOSSystemState`]
|
|
||||||
fn unite_raw(&mut self, other: &ReducedFreeRTOSSystemState, input: &Vec<u8>) -> bool {
|
|
||||||
if &self.base!=other {return false;}
|
|
||||||
self.variants.push(VariantTuple::from(other, input.clone()));
|
|
||||||
self.variants.dedup();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
/// add a Varint from a [`RefinedFreeRTOSSystemState`], if it's interesting
|
|
||||||
fn unite_interesting(&mut self, other: &ReducedFreeRTOSSystemState, input: &Vec<u8>) -> bool {
|
|
||||||
// if &self.base!=other {return false;}
|
|
||||||
// let interesting =
|
|
||||||
// self.variants.iter().all(|x| x.end_tick-x.start_tick<other.end_tick-other.tick) || // longest variant
|
|
||||||
// self.variants.iter().all(|x| x.end_tick-x.start_tick>other.end_tick-other.tick) || // shortest variant
|
|
||||||
// self.variants.iter().all(|x| x.input_counter>other.input_counter) || // longest input
|
|
||||||
// self.variants.iter().all(|x| x.input_counter<other.input_counter); // shortest input
|
|
||||||
// if interesting {
|
|
||||||
// let var = VariantTuple::from(other, input.clone());
|
|
||||||
// self.variants.push(var);
|
|
||||||
// }
|
|
||||||
// return interesting;
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
pub fn get_taskname(&self) -> &str {
|
|
||||||
&self.base.current_task.task_name
|
|
||||||
}
|
|
||||||
pub fn get_input_counts(&self) -> Vec<u32> {
|
|
||||||
self.variants.iter().map(|x| x.input_counter).collect()
|
|
||||||
}
|
|
||||||
pub fn pretty_print(&self) -> String {
|
|
||||||
let mut ret = String::new();
|
|
||||||
ret.push_str(&format!("{}",&self.base.current_task.task_name));
|
|
||||||
ret.push_str(";Rl:");
|
|
||||||
for i in &self.base.ready_list_after {
|
|
||||||
ret.push_str(&format!(";{}",i.task_name));
|
|
||||||
}
|
|
||||||
ret.push_str(";Dl:");
|
|
||||||
for i in &self.base.delay_list_after {
|
|
||||||
ret.push_str(&format!(";{}",i.task_name));
|
|
||||||
}
|
|
||||||
// println!("{}",ret);
|
|
||||||
ret
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl PartialEq for SysGraphNode {
|
|
||||||
fn eq(&self, other: &SysGraphNode) -> bool {
|
|
||||||
self.base==other.base
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wrapper around Vec<RefinedFreeRTOSSystemState> to attach as Metadata
|
|
||||||
#[derive(Debug, Default, Serialize, Deserialize, Clone)]
|
|
||||||
pub struct SysGraphMetadata {
|
|
||||||
pub inner: Vec<NodeIndex>,
|
|
||||||
indices: Vec<usize>,
|
|
||||||
tcref: isize,
|
|
||||||
}
|
|
||||||
impl SysGraphMetadata {
|
|
||||||
pub fn new(inner: Vec<NodeIndex>) -> Self{
|
|
||||||
Self {indices: inner.iter().map(|x| x.index()).collect(), inner: inner, tcref: 0}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// impl AsSlice for SysGraphMetadata {
|
|
||||||
// /// Convert the slice of system-states to a slice of hashes over enumerated states
|
|
||||||
// fn as_slice(&self) -> &[usize] {
|
|
||||||
// self.indices.as_slice()
|
|
||||||
// }
|
|
||||||
|
|
||||||
// type Entry = usize;
|
|
||||||
// }
|
|
||||||
|
|
||||||
impl HasRefCnt for SysGraphMetadata {
|
|
||||||
fn refcnt(&self) -> isize {
|
|
||||||
self.tcref
|
|
||||||
}
|
|
||||||
|
|
||||||
fn refcnt_mut(&mut self) -> &mut isize {
|
|
||||||
&mut self.tcref
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
libafl_bolts::impl_serdeany!(SysGraphMetadata);
|
|
||||||
|
|
||||||
pub type GraphMaximizerCorpusScheduler<CS, O> =
|
|
||||||
MinimizerScheduler<CS, MaxTimeFavFactor<<CS as UsesState>::State>,SysGraphMetadata,O>;
|
|
||||||
|
|
||||||
//============================= Graph Feedback
|
|
||||||
|
|
||||||
/// Improved System State Graph
|
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug, SerdeAny)]
|
|
||||||
pub struct SysGraphFeedbackState
|
|
||||||
{
|
|
||||||
pub graph: DiGraph<SysGraphNode, ()>,
|
|
||||||
entrypoint: NodeIndex,
|
|
||||||
exit: NodeIndex,
|
|
||||||
name: Cow<'static, str>
|
|
||||||
}
|
|
||||||
impl SysGraphFeedbackState
|
|
||||||
{
|
|
||||||
pub fn new() -> Self {
|
|
||||||
let mut graph = DiGraph::<SysGraphNode, ()>::new();
|
|
||||||
let mut entry = SysGraphNode::default();
|
|
||||||
entry.base.current_task.task_name="Start".to_string();
|
|
||||||
let mut exit = SysGraphNode::default();
|
|
||||||
exit.base.current_task.task_name="End".to_string();
|
|
||||||
let entry = graph.add_node(entry);
|
|
||||||
let exit = graph.add_node(exit);
|
|
||||||
Self {graph: graph, entrypoint: entry, exit: exit, name: Cow::from(String::from("SysMap"))}
|
|
||||||
}
|
|
||||||
fn insert(&mut self, list: Vec<ReducedFreeRTOSSystemState>, input: &Vec<u8>) {
|
|
||||||
let mut current_index = self.entrypoint;
|
|
||||||
for n in list {
|
|
||||||
let mut done = false;
|
|
||||||
for i in self.graph.neighbors_directed(current_index, Direction::Outgoing) {
|
|
||||||
if n == self.graph[i].base {
|
|
||||||
done = true;
|
|
||||||
current_index = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !done {
|
|
||||||
let j = self.graph.add_node(SysGraphNode::from(n,input.clone()));
|
|
||||||
self.graph.add_edge(current_index, j, ());
|
|
||||||
current_index = j;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/// Try adding a system state path from a [Vec<RefinedFreeRTOSSystemState>], return true if the path was interesting
|
|
||||||
fn update(&mut self, list: &Vec<ReducedFreeRTOSSystemState>, input: &Vec<u8>) -> (bool, Vec<NodeIndex>) {
|
|
||||||
let mut current_index = self.entrypoint;
|
|
||||||
let mut novel = false;
|
|
||||||
let mut trace : Vec<NodeIndex> = vec![current_index];
|
|
||||||
for n in list {
|
|
||||||
let mut matching : Option<NodeIndex> = None;
|
|
||||||
for i in self.graph.node_indices() {
|
|
||||||
let tmp = &self.graph[i];
|
|
||||||
if n == &tmp.base {
|
|
||||||
matching = Some(i);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
match matching {
|
|
||||||
None => {
|
|
||||||
novel = true;
|
|
||||||
let j = self.graph.add_node(SysGraphNode::from(n.clone(),input.clone()));
|
|
||||||
self.graph.update_edge(current_index, j, ());
|
|
||||||
current_index = j;
|
|
||||||
},
|
|
||||||
Some(i) => {
|
|
||||||
novel |= self.graph[i].unite_interesting(&n, input);
|
|
||||||
self.graph.update_edge(current_index, i, ());
|
|
||||||
current_index = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
trace.push(current_index);
|
|
||||||
}
|
|
||||||
if current_index != self.entrypoint {
|
|
||||||
self.graph.update_edge(current_index, self.exit, ()); // every path ends in the exit noded
|
|
||||||
}
|
|
||||||
return (novel, trace);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Named for SysGraphFeedbackState
|
|
||||||
{
|
|
||||||
#[inline]
|
|
||||||
fn name(&self) -> &Cow<'static, str> {
|
|
||||||
&self.name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Default for SysGraphFeedbackState {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self::new()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl SysGraphFeedbackState
|
|
||||||
{
|
|
||||||
fn reset(&mut self) -> Result<(), Error> {
|
|
||||||
self.graph.clear();
|
|
||||||
let mut entry = SysGraphNode::default();
|
|
||||||
entry.base.current_task.task_name="Start".to_string();
|
|
||||||
let mut exit = SysGraphNode::default();
|
|
||||||
exit.base.current_task.task_name="End".to_string();
|
|
||||||
self.entrypoint = self.graph.add_node(entry);
|
|
||||||
self.exit = self.graph.add_node(exit);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A Feedback reporting novel System-State Transitions. Depends on [`QemuSystemStateObserver`]
|
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug, Default)]
|
|
||||||
pub struct SysMapFeedback
|
|
||||||
{
|
|
||||||
name: Cow<'static, str>,
|
|
||||||
last_trace: Option<Vec<NodeIndex>>,
|
|
||||||
}
|
|
||||||
impl SysMapFeedback {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self {name: Cow::from(String::from("SysMapFeedback")), last_trace: None }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<S> Feedback<S> for SysMapFeedback
|
|
||||||
where
|
|
||||||
S: State + UsesInput + MaybeHasClientPerfMonitor + HasNamedMetadata,
|
|
||||||
S::Input: HasTargetBytes,
|
|
||||||
{
|
|
||||||
#[allow(clippy::wrong_self_convention)]
|
|
||||||
fn is_interesting<EM, OT>(
|
|
||||||
&mut self,
|
|
||||||
state: &mut S,
|
|
||||||
_manager: &mut EM,
|
|
||||||
_input: &S::Input,
|
|
||||||
observers: &OT,
|
|
||||||
_exit_kind: &ExitKind,
|
|
||||||
) -> Result<bool, Error>
|
|
||||||
where
|
|
||||||
EM: EventFirer<State = S>,
|
|
||||||
OT: ObserversTuple<S>,
|
|
||||||
{
|
|
||||||
let observer = observers.match_name::<QemuSystemStateObserver>("systemstate")
|
|
||||||
.expect("QemuSystemStateObserver not found");
|
|
||||||
let feedbackstate = match state
|
|
||||||
.named_metadata_map_mut()
|
|
||||||
.get_mut::<SysGraphFeedbackState>("SysMap") {
|
|
||||||
Some(s) => s,
|
|
||||||
None => {
|
|
||||||
let n=SysGraphFeedbackState::default();
|
|
||||||
state.named_metadata_map_mut().insert("SysMap",n);
|
|
||||||
state.named_metadata_map_mut().get_mut::<SysGraphFeedbackState>("SysMap").unwrap()
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let ret = feedbackstate.update(&observer.last_run, &observer.last_input);
|
|
||||||
self.last_trace = Some(ret.1);
|
|
||||||
Ok(ret.0)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Append to the testcase the generated metadata in case of a new corpus item
|
|
||||||
#[inline]
|
|
||||||
fn append_metadata<EM, OT>(&mut self, _state: &mut S, _manager: &mut EM, _observers: &OT, testcase: &mut Testcase<S::Input>) -> Result<(), Error> {
|
|
||||||
let a = self.last_trace.take();
|
|
||||||
match a {
|
|
||||||
Some(s) => testcase.metadata_map_mut().insert(SysGraphMetadata::new(s)),
|
|
||||||
None => (),
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Discard the stored metadata in case that the testcase is not added to the corpus
|
|
||||||
#[inline]
|
|
||||||
fn discard_metadata(&mut self, _state: &mut S, _input: &S::Input) -> Result<(), Error> {
|
|
||||||
self.last_trace = None;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Named for SysMapFeedback
|
|
||||||
{
|
|
||||||
#[inline]
|
|
||||||
fn name(&self) -> &Cow<'static, str> {
|
|
||||||
&self.name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//============================= Mutators
|
|
||||||
//=============================== Snippets
|
|
||||||
// pub struct RandGraphSnippetMutator<I, S>
|
|
||||||
// where
|
|
||||||
// I: Input + HasBytesVec,
|
|
||||||
// S: HasRand + HasMetadata + HasCorpus<I> + HasSolutions<I>,
|
|
||||||
// {
|
|
||||||
// phantom: PhantomData<(I, S)>,
|
|
||||||
// }
|
|
||||||
// impl<I, S> RandGraphSnippetMutator<I, S>
|
|
||||||
// where
|
|
||||||
// I: Input + HasBytesVec,
|
|
||||||
// S: HasRand + HasMetadata + HasCorpus<I> + HasSolutions<I>,
|
|
||||||
// {
|
|
||||||
// pub fn new() -> Self {
|
|
||||||
// RandGraphSnippetMutator{phantom: PhantomData}
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// impl<I, S> Mutator<I, S> for RandGraphSnippetMutator<I, S>
|
|
||||||
// where
|
|
||||||
// I: Input + HasBytesVec,
|
|
||||||
// S: HasRand + HasMetadata + HasCorpus<I> + HasSolutions<I>,
|
|
||||||
// {
|
|
||||||
// fn mutate(
|
|
||||||
// &mut self,
|
|
||||||
// state: &mut S,
|
|
||||||
// input: &mut I,
|
|
||||||
// _stage_idx: i32
|
|
||||||
// ) -> Result<MutationResult, Error>
|
|
||||||
// {
|
|
||||||
// // need our own random generator, because borrowing rules
|
|
||||||
// let mut myrand = StdRand::new();
|
|
||||||
// let tmp = &mut state.rand_mut();
|
|
||||||
// myrand.set_seed(tmp.next());
|
|
||||||
// drop(tmp);
|
|
||||||
|
|
||||||
// let feedbackstate = state
|
|
||||||
// .feedback_states()
|
|
||||||
// .match_name::<SysGraphFeedbackState>("SysMap")
|
|
||||||
// .unwrap();
|
|
||||||
// let g = &feedbackstate.graph;
|
|
||||||
// let tmp = state.metadata().get::<SysGraphMetadata>();
|
|
||||||
// if tmp.is_none() { // if there are no metadata it was probably not interesting anyways
|
|
||||||
// return Ok(MutationResult::Skipped);
|
|
||||||
// }
|
|
||||||
// let trace =tmp.expect("SysGraphMetadata not found");
|
|
||||||
// // follow the path, extract snippets from last reads, find common snippets.
|
|
||||||
// // those are likley keys parts. choose random parts from other sibling traces
|
|
||||||
// let sibling_inputs : Vec<&Vec<u8>>= g[*trace.inner.last().unwrap()].variants.iter().map(|x| &x.input).collect();
|
|
||||||
// let mut snippet_collector = vec![];
|
|
||||||
// let mut per_input_counters = HashMap::<&Vec<u8>,usize>::new(); // ugly workaround to track multiple inputs
|
|
||||||
// for t in &trace.inner {
|
|
||||||
// let node = &g[*t];
|
|
||||||
// let mut per_node_snippets = HashMap::<&Vec<u8>,&[u8]>::new();
|
|
||||||
// for v in &node.variants {
|
|
||||||
// match per_input_counters.get_mut(&v.input) {
|
|
||||||
// None => {
|
|
||||||
// if sibling_inputs.iter().any(|x| *x==&v.input) { // only collect info about siblin inputs from target
|
|
||||||
// per_input_counters.insert(&v.input, v.input_counter.try_into().unwrap());
|
|
||||||
// }
|
|
||||||
// },
|
|
||||||
// Some(x) => {
|
|
||||||
// let x_u = *x;
|
|
||||||
// if x_u<v.input_counter as usize {
|
|
||||||
// *x=v.input_counter as usize;
|
|
||||||
// per_node_snippets.insert(&v.input,&v.input[x_u..v.input_counter as usize]);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// snippet_collector.push(per_node_snippets);
|
|
||||||
// }
|
|
||||||
// let mut new_input : Vec<u8> = vec![];
|
|
||||||
// for c in snippet_collector {
|
|
||||||
// new_input.extend_from_slice(myrand.choose(c).1);
|
|
||||||
// }
|
|
||||||
// for i in new_input.iter().enumerate() {
|
|
||||||
// input.bytes_mut()[i.0]=*i.1;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// Ok(MutationResult::Mutated)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// fn post_exec(
|
|
||||||
// &mut self,
|
|
||||||
// _state: &mut S,
|
|
||||||
// _stage_idx: i32,
|
|
||||||
// _corpus_idx: Option<usize>
|
|
||||||
// ) -> Result<(), Error> {
|
|
||||||
// Ok(())
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// impl<I, S> Named for RandGraphSnippetMutator<I, S>
|
|
||||||
// where
|
|
||||||
// I: Input + HasBytesVec,
|
|
||||||
// S: HasRand + HasMetadata + HasCorpus<I> + HasSolutions<I>,
|
|
||||||
// {
|
|
||||||
// fn name(&self) -> &str {
|
|
||||||
// "RandGraphSnippetMutator"
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// //=============================== Snippets
|
|
||||||
// pub struct RandInputSnippetMutator<I, S>
|
|
||||||
// where
|
|
||||||
// I: Input + HasBytesVec,
|
|
||||||
// S: HasRand + HasMetadata + HasCorpus<I> + HasSolutions<I>,
|
|
||||||
// {
|
|
||||||
// phantom: PhantomData<(I, S)>,
|
|
||||||
// }
|
|
||||||
// impl<I, S> RandInputSnippetMutator<I, S>
|
|
||||||
// where
|
|
||||||
// I: Input + HasBytesVec,
|
|
||||||
// S: HasRand + HasMetadata + HasCorpus<I> + HasSolutions<I>,
|
|
||||||
// {
|
|
||||||
// pub fn new() -> Self {
|
|
||||||
// RandInputSnippetMutator{phantom: PhantomData}
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// impl<I, S> Mutator<I, S> for RandInputSnippetMutator<I, S>
|
|
||||||
// where
|
|
||||||
// I: Input + HasBytesVec,
|
|
||||||
// S: HasRand + HasMetadata + HasCorpus<I> + HasSolutions<I>,
|
|
||||||
// {
|
|
||||||
// fn mutate(
|
|
||||||
// &mut self,
|
|
||||||
// state: &mut S,
|
|
||||||
// input: &mut I,
|
|
||||||
// _stage_idx: i32
|
|
||||||
// ) -> Result<MutationResult, Error>
|
|
||||||
// {
|
|
||||||
// // need our own random generator, because borrowing rules
|
|
||||||
// let mut myrand = StdRand::new();
|
|
||||||
// let tmp = &mut state.rand_mut();
|
|
||||||
// myrand.set_seed(tmp.next());
|
|
||||||
// drop(tmp);
|
|
||||||
|
|
||||||
// let feedbackstate = state
|
|
||||||
// .feedback_states()
|
|
||||||
// .match_name::<SysGraphFeedbackState>("SysMap")
|
|
||||||
// .unwrap();
|
|
||||||
// let g = &feedbackstate.graph;
|
|
||||||
// let tmp = state.metadata().get::<SysGraphMetadata>();
|
|
||||||
// if tmp.is_none() { // if there are no metadata it was probably not interesting anyways
|
|
||||||
// return Ok(MutationResult::Skipped);
|
|
||||||
// }
|
|
||||||
// let trace = tmp.expect("SysGraphMetadata not found");
|
|
||||||
|
|
||||||
// let mut collection : Vec<Vec<u8>> = Vec::new();
|
|
||||||
// let mut current_pointer : usize = 0;
|
|
||||||
// for t in &trace.inner {
|
|
||||||
// let node = &g[*t];
|
|
||||||
// for v in &node.variants {
|
|
||||||
// if v.input == input.bytes() {
|
|
||||||
// if v.input_counter > current_pointer.try_into().unwrap() {
|
|
||||||
// collection.push(v.input[current_pointer..v.input_counter as usize].to_owned());
|
|
||||||
// current_pointer = v.input_counter as usize;
|
|
||||||
// }
|
|
||||||
// break;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// let index_to_mutate = myrand.below(collection.len() as u64) as usize;
|
|
||||||
// for i in 0..collection[index_to_mutate].len() {
|
|
||||||
// collection[index_to_mutate][i] = myrand.below(0xFF) as u8;
|
|
||||||
// }
|
|
||||||
// for i in collection.concat().iter().enumerate() {
|
|
||||||
// input.bytes_mut()[i.0]=*i.1;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// Ok(MutationResult::Mutated)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// fn post_exec(
|
|
||||||
// &mut self,
|
|
||||||
// _state: &mut S,
|
|
||||||
// _stage_idx: i32,
|
|
||||||
// _corpus_idx: Option<usize>
|
|
||||||
// ) -> Result<(), Error> {
|
|
||||||
// Ok(())
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// impl<I, S> Named for RandInputSnippetMutator<I, S>
|
|
||||||
// where
|
|
||||||
// I: Input + HasBytesVec,
|
|
||||||
// S: HasRand + HasMetadata + HasCorpus<I> + HasSolutions<I>,
|
|
||||||
// {
|
|
||||||
// fn name(&self) -> &str {
|
|
||||||
// "RandInputSnippetMutator"
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// //=============================== Suffix
|
|
||||||
// pub struct RandGraphSuffixMutator<I, S>
|
|
||||||
// where
|
|
||||||
// I: Input + HasBytesVec,
|
|
||||||
// S: HasRand + HasMetadata + HasCorpus<I> + HasSolutions<I>,
|
|
||||||
// {
|
|
||||||
// phantom: PhantomData<(I, S)>,
|
|
||||||
// }
|
|
||||||
// impl<I, S> RandGraphSuffixMutator<I, S>
|
|
||||||
// where
|
|
||||||
// I: Input + HasBytesVec,
|
|
||||||
// S: HasRand + HasMetadata + HasCorpus<I> + HasSolutions<I>,
|
|
||||||
// {
|
|
||||||
// pub fn new() -> Self {
|
|
||||||
// RandGraphSuffixMutator{phantom: PhantomData}
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// impl<I, S> Mutator<I, S> for RandGraphSuffixMutator<I, S>
|
|
||||||
// where
|
|
||||||
// I: Input + HasBytesVec,
|
|
||||||
// S: HasRand + HasMetadata + HasCorpus<I> + HasSolutions<I>,
|
|
||||||
// {
|
|
||||||
// fn mutate(
|
|
||||||
// &mut self,
|
|
||||||
// state: &mut S,
|
|
||||||
// input: &mut I,
|
|
||||||
// _stage_idx: i32
|
|
||||||
// ) -> Result<MutationResult, Error>
|
|
||||||
// {
|
|
||||||
// // need our own random generator, because borrowing rules
|
|
||||||
// let mut myrand = StdRand::new();
|
|
||||||
// let tmp = &mut state.rand_mut();
|
|
||||||
// myrand.set_seed(tmp.next());
|
|
||||||
// drop(tmp);
|
|
||||||
|
|
||||||
// let feedbackstate = state
|
|
||||||
// .feedback_states()
|
|
||||||
// .match_name::<SysGraphFeedbackState>("SysMap")
|
|
||||||
// .unwrap();
|
|
||||||
// let g = &feedbackstate.graph;
|
|
||||||
// let tmp = state.metadata().get::<SysGraphMetadata>();
|
|
||||||
// if tmp.is_none() { // if there are no metadata it was probably not interesting anyways
|
|
||||||
// return Ok(MutationResult::Skipped);
|
|
||||||
// }
|
|
||||||
// let trace =tmp.expect("SysGraphMetadata not found");
|
|
||||||
// // follow the path, extract snippets from last reads, find common snippets.
|
|
||||||
// // those are likley keys parts. choose random parts from other sibling traces
|
|
||||||
// let inp_c_end = g[*trace.inner.last().unwrap()].base.input_counter;
|
|
||||||
// let mut num_to_reverse = myrand.below(trace.inner.len().try_into().unwrap());
|
|
||||||
// for t in trace.inner.iter().rev() {
|
|
||||||
// let int_c_prefix = g[*t].base.input_counter;
|
|
||||||
// if int_c_prefix < inp_c_end {
|
|
||||||
// num_to_reverse-=1;
|
|
||||||
// if num_to_reverse<=0 {
|
|
||||||
// let mut new_input=input.bytes()[..(int_c_prefix as usize)].to_vec();
|
|
||||||
// let mut ext : Vec<u8> = (int_c_prefix..inp_c_end).map(|_| myrand.next().to_le_bytes()).flatten().collect();
|
|
||||||
// new_input.append(&mut ext);
|
|
||||||
// for i in new_input.iter().enumerate() {
|
|
||||||
// if input.bytes_mut().len()>i.0 {
|
|
||||||
// input.bytes_mut()[i.0]=*i.1;
|
|
||||||
// }
|
|
||||||
// else { break };
|
|
||||||
// }
|
|
||||||
// break;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// Ok(MutationResult::Mutated)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// fn post_exec(
|
|
||||||
// &mut self,
|
|
||||||
// _state: &mut S,
|
|
||||||
// _stage_idx: i32,
|
|
||||||
// _corpus_idx: Option<usize>
|
|
||||||
// ) -> Result<(), Error> {
|
|
||||||
// Ok(())
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// impl<I, S> Named for RandGraphSuffixMutator<I, S>
|
|
||||||
// where
|
|
||||||
// I: Input + HasBytesVec,
|
|
||||||
// S: HasRand + HasMetadata + HasCorpus<I> + HasSolutions<I>,
|
|
||||||
// {
|
|
||||||
// fn name(&self) -> &str {
|
|
||||||
// "RandGraphSuffixMutator"
|
|
||||||
// }
|
|
||||||
// }
|
|
@ -1,21 +1,13 @@
|
|||||||
use std::cell::UnsafeCell;
|
|
||||||
use std::io::Write;
|
|
||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
use libafl::prelude::ExitKind;
|
use libafl::prelude::ExitKind;
|
||||||
use libafl::prelude::UsesInput;
|
use libafl::prelude::UsesInput;
|
||||||
use libafl_qemu::read_user_reg_unchecked;
|
use libafl_qemu::read_user_reg_unchecked;
|
||||||
use libafl_qemu::Emulator;
|
|
||||||
use libafl_qemu::GuestAddr;
|
use libafl_qemu::GuestAddr;
|
||||||
use libafl_qemu::GuestPhysAddr;
|
|
||||||
use libafl_qemu::GuestReg;
|
|
||||||
use libafl_qemu::Qemu;
|
|
||||||
use libafl_qemu::QemuHooks;
|
use libafl_qemu::QemuHooks;
|
||||||
use libafl_qemu::edges::QemuEdgesMapMetadata;
|
|
||||||
use libafl_qemu::emu;
|
|
||||||
use libafl_qemu::hooks;
|
|
||||||
use libafl_qemu::Hook;
|
use libafl_qemu::Hook;
|
||||||
// use crate::systemstate::extract_abbs_from_trace;
|
use libafl_qemu::helpers::{QemuHelper, QemuHelperTuple};
|
||||||
|
|
||||||
use crate::systemstate::RawFreeRTOSSystemState;
|
use crate::systemstate::RawFreeRTOSSystemState;
|
||||||
use crate::systemstate::CURRENT_SYSTEMSTATE_VEC;
|
use crate::systemstate::CURRENT_SYSTEMSTATE_VEC;
|
||||||
use crate::systemstate::NUM_PRIOS;
|
use crate::systemstate::NUM_PRIOS;
|
||||||
@ -26,18 +18,7 @@ use super::freertos::rtos_struct::*;
|
|||||||
use super::freertos;
|
use super::freertos;
|
||||||
use super::CaptureEvent;
|
use super::CaptureEvent;
|
||||||
|
|
||||||
use libafl_qemu::{
|
|
||||||
helpers::{QemuHelper, QemuHelperTuple},
|
|
||||||
// edges::SAVED_JUMP,
|
|
||||||
};
|
|
||||||
|
|
||||||
//============================= Struct definitions
|
|
||||||
|
|
||||||
pub static mut INTR_OFFSET : Option<u64> = None;
|
|
||||||
pub static mut INTR_DONE : bool = true;
|
|
||||||
|
|
||||||
// only used when inputs are injected
|
|
||||||
pub static mut NEXT_INPUT : Vec<u8> = Vec::new();
|
|
||||||
|
|
||||||
//============================= API symbols
|
//============================= API symbols
|
||||||
|
|
||||||
@ -235,7 +216,7 @@ fn trigger_collection(emulator: &libafl_qemu::Qemu, edge: (GuestAddr, GuestAddr)
|
|||||||
// println!("{:?}",std::str::from_utf8(¤t_tcb.pcTaskName));
|
// println!("{:?}",std::str::from_utf8(¤t_tcb.pcTaskName));
|
||||||
let critical : void_ptr = freertos::emu_lookup::lookup(emulator, h.critical_addr);
|
let critical : void_ptr = freertos::emu_lookup::lookup(emulator, h.critical_addr);
|
||||||
let suspended : void_ptr = freertos::emu_lookup::lookup(emulator, h.scheduler_lock_addr);
|
let suspended : void_ptr = freertos::emu_lookup::lookup(emulator, h.scheduler_lock_addr);
|
||||||
let running : void_ptr = freertos::emu_lookup::lookup(emulator, h.scheduler_running_addr);
|
let _running : void_ptr = freertos::emu_lookup::lookup(emulator, h.scheduler_running_addr);
|
||||||
|
|
||||||
systemstate.current_tcb = freertos::emu_lookup::lookup(emulator,curr_tcb_addr);
|
systemstate.current_tcb = freertos::emu_lookup::lookup(emulator,curr_tcb_addr);
|
||||||
// During ISRs it is only safe to extract structs if they are not currently being modified
|
// During ISRs it is only safe to extract structs if they are not currently being modified
|
||||||
|
@ -3,13 +3,11 @@ use std::collections::hash_map::DefaultHasher;
|
|||||||
use std::fmt;
|
use std::fmt;
|
||||||
use hashbrown::HashSet;
|
use hashbrown::HashSet;
|
||||||
use libafl_bolts::HasRefCnt;
|
use libafl_bolts::HasRefCnt;
|
||||||
use libafl_bolts::AsSlice;
|
|
||||||
use libafl_qemu::GuestAddr;
|
use libafl_qemu::GuestAddr;
|
||||||
use std::hash::Hasher;
|
use std::hash::Hasher;
|
||||||
use std::hash::Hash;
|
use std::hash::Hash;
|
||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::rc::Rc;
|
|
||||||
|
|
||||||
use freertos::TCB_t;
|
use freertos::TCB_t;
|
||||||
|
|
||||||
@ -17,7 +15,6 @@ pub mod freertos;
|
|||||||
pub mod helpers;
|
pub mod helpers;
|
||||||
pub mod observers;
|
pub mod observers;
|
||||||
pub mod feedbacks;
|
pub mod feedbacks;
|
||||||
pub mod graph;
|
|
||||||
pub mod schedulers;
|
pub mod schedulers;
|
||||||
pub mod stg;
|
pub mod stg;
|
||||||
|
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
// use crate::systemstate::IRQ_INPUT_BYTES_NUMBER;
|
|
||||||
use libafl::prelude::ExitKind;
|
use libafl::prelude::ExitKind;
|
||||||
use libafl::{inputs::HasTargetBytes, prelude::UsesInput};
|
use libafl::{inputs::HasTargetBytes, prelude::UsesInput};
|
||||||
use libafl_bolts::HasLen;
|
use libafl_bolts::HasLen;
|
||||||
@ -54,11 +53,11 @@ where
|
|||||||
fn post_exec(&mut self, _state: &mut S, _input: &S::Input, _exit_kind: &ExitKind) -> Result<(), Error> {
|
fn post_exec(&mut self, _state: &mut S, _input: &S::Input, _exit_kind: &ExitKind) -> Result<(), Error> {
|
||||||
// unsafe {self.last_run = invalidate_ineffective_isr(refine_system_states(&mut CURRENT_SYSTEMSTATE_VEC));}
|
// unsafe {self.last_run = invalidate_ineffective_isr(refine_system_states(&mut CURRENT_SYSTEMSTATE_VEC));}
|
||||||
unsafe {
|
unsafe {
|
||||||
let mut temp = refine_system_states(&mut CURRENT_SYSTEMSTATE_VEC);
|
let temp = refine_system_states(CURRENT_SYSTEMSTATE_VEC.drain(..).collect());
|
||||||
// fix_broken_trace(&mut temp.1);
|
// fix_broken_trace(&mut temp.1);
|
||||||
self.last_run = temp.0.clone();
|
self.last_run = temp.0.clone();
|
||||||
// println!("{:?}",temp);
|
// println!("{:?}",temp);
|
||||||
let mut temp = states2intervals(temp.0, temp.1);
|
let temp = states2intervals(temp.0, temp.1);
|
||||||
self.last_trace = temp.0;
|
self.last_trace = temp.0;
|
||||||
self.last_states = temp.1;
|
self.last_states = temp.1;
|
||||||
self.success = temp.2;
|
self.success = temp.2;
|
||||||
@ -138,7 +137,7 @@ fn tcb_list_to_vec_cached(list: List_t, dump: &mut HashMap<u32,rtos_struct>) ->
|
|||||||
ret
|
ret
|
||||||
}
|
}
|
||||||
/// Drains a List of raw SystemStates to produce a refined trace
|
/// Drains a List of raw SystemStates to produce a refined trace
|
||||||
fn refine_system_states(input: &mut Vec<RawFreeRTOSSystemState>) -> (Vec<ReducedFreeRTOSSystemState>, Vec<(u64, CaptureEvent, String, (u32, u32))>) {
|
fn refine_system_states(mut input: Vec<RawFreeRTOSSystemState>) -> (Vec<ReducedFreeRTOSSystemState>, Vec<(u64, CaptureEvent, String, (u32, u32))>) {
|
||||||
let mut ret = (Vec::<_>::new(), Vec::<_>::new());
|
let mut ret = (Vec::<_>::new(), Vec::<_>::new());
|
||||||
for mut i in input.drain(..) {
|
for mut i in input.drain(..) {
|
||||||
let cur = RefinedTCB::from_tcb_owned(i.current_tcb);
|
let cur = RefinedTCB::from_tcb_owned(i.current_tcb);
|
||||||
@ -354,39 +353,39 @@ fn add_abb_info(trace: &mut Vec<ExecInterval>, table: &HashMap<u64, ReducedFreeR
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// restore the isr/api begin/end invariant
|
// /// restore the isr/api begin/end invariant
|
||||||
fn fix_broken_trace(meta: &mut Vec<(u64, CaptureEvent, String, (Option<u32>, Option<u32>))>) {
|
// fn fix_broken_trace(meta: &mut Vec<(u64, CaptureEvent, String, (Option<u32>, Option<u32>))>) {
|
||||||
for i in meta.iter_mut() {
|
// for i in meta.iter_mut() {
|
||||||
if i.1 == CaptureEvent::APIStart && i.2.ends_with("FromISR") {
|
// if i.1 == CaptureEvent::APIStart && i.2.ends_with("FromISR") {
|
||||||
i.1 = CaptureEvent::ISREnd;
|
// i.1 = CaptureEvent::ISREnd;
|
||||||
i.2 = "isr_starter".to_string();
|
// i.2 = "isr_starter".to_string();
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
/// invalidate subsequent intervals of equal states where an ISREnd follows an ISRStart. If the interrupt had no effect on the system we, are not interested.
|
// /// invalidate subsequent intervals of equal states where an ISREnd follows an ISRStart. If the interrupt had no effect on the system we, are not interested.
|
||||||
fn invalidate_ineffective_isr(trace: &mut Vec<ExecInterval>) {
|
// fn invalidate_ineffective_isr(trace: &mut Vec<ExecInterval>) {
|
||||||
let mut i = 0;
|
// let mut i = 0;
|
||||||
while i < trace.len() - 1 {
|
// while i < trace.len() - 1 {
|
||||||
if trace[i].is_valid() &&
|
// if trace[i].is_valid() &&
|
||||||
matches!(trace[i].start_capture.0, CaptureEvent::ISRStart) && matches!(trace[i].end_capture.0, CaptureEvent::ISREnd) &&
|
// matches!(trace[i].start_capture.0, CaptureEvent::ISRStart) && matches!(trace[i].end_capture.0, CaptureEvent::ISREnd) &&
|
||||||
trace[i].start_capture.1 == trace[i].end_capture.1 && trace[i].start_state == trace[i].end_state
|
// trace[i].start_capture.1 == trace[i].end_capture.1 && trace[i].start_state == trace[i].end_state
|
||||||
{
|
// {
|
||||||
trace[i].invaildate();
|
// trace[i].invaildate();
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
/// merge a sequence of intervals of the same state+abb. jump over all invalid blocks.
|
// /// merge a sequence of intervals of the same state+abb. jump over all invalid blocks.
|
||||||
fn merge_subsequent_abbs(trace: &mut Vec<ExecInterval>) {
|
// fn merge_subsequent_abbs(trace: &mut Vec<ExecInterval>) {
|
||||||
let mut i = 1;
|
// let mut i = 1;
|
||||||
let mut lst_valid=0;
|
// let mut lst_valid=0;
|
||||||
while i < trace.len() - 1 {
|
// while i < trace.len() - 1 {
|
||||||
if trace[i].is_valid() {
|
// if trace[i].is_valid() {
|
||||||
let mut temp = trace[i].clone();
|
// let mut temp = trace[i].clone();
|
||||||
trace[lst_valid].try_unite_with_later_interval(&mut temp);
|
// trace[lst_valid].try_unite_with_later_interval(&mut temp);
|
||||||
trace[i] = temp;
|
// trace[i] = temp;
|
||||||
lst_valid = i;
|
// lst_valid = i;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
@ -1,14 +1,14 @@
|
|||||||
//! The Minimizer schedulers are a family of corpus schedulers that feed the fuzzer
|
//! The Minimizer schedulers are a family of corpus schedulers that feed the fuzzer
|
||||||
//! with testcases only from a subset of the total corpus.
|
//! with testcases only from a subset of the total corpus.
|
||||||
|
|
||||||
use core::{marker::PhantomData};
|
use core::marker::PhantomData;
|
||||||
use std::{cmp::{max, min}, mem::swap, borrow::BorrowMut};
|
use std::{cmp::{max, min}, mem::swap};
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use libafl_bolts::{rands::Rand, serdeany::SerdeAny, AsSlice, HasRefCnt, HasLen};
|
use libafl_bolts::{rands::Rand, HasLen};
|
||||||
use libafl::{
|
use libafl::{
|
||||||
corpus::{Corpus, Testcase},
|
corpus::Corpus,
|
||||||
inputs::UsesInput,
|
inputs::UsesInput,
|
||||||
schedulers::{Scheduler, TestcaseScore, minimizer::DEFAULT_SKIP_NON_FAVORED_PROB },
|
schedulers::{Scheduler, TestcaseScore, minimizer::DEFAULT_SKIP_NON_FAVORED_PROB },
|
||||||
state::{HasCorpus, HasRand, UsesState, State},
|
state::{HasCorpus, HasRand, UsesState, State},
|
||||||
@ -40,7 +40,7 @@ impl LongestTracesMetadata {
|
|||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct LongestTraceScheduler<CS> {
|
pub struct LongestTraceScheduler<CS> {
|
||||||
base: CS,
|
base: CS,
|
||||||
skip_non_favored_prob: usize,
|
skip_non_favored_prob: f64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<CS> UsesState for LongestTraceScheduler<CS>
|
impl<CS> UsesState for LongestTraceScheduler<CS>
|
||||||
@ -104,7 +104,7 @@ where
|
|||||||
.get::<STGNodeMetadata>().map_or(0, |x| x.nodes.len());
|
.get::<STGNodeMetadata>().map_or(0, |x| x.nodes.len());
|
||||||
let m = self.get_update_trace_length(state,l);
|
let m = self.get_update_trace_length(state,l);
|
||||||
state.rand_mut().below(m as usize) > l
|
state.rand_mut().below(m as usize) > l
|
||||||
} && state.rand_mut().below(100) < self.skip_non_favored_prob
|
} && state.rand_mut().coinflip(self.skip_non_favored_prob)
|
||||||
{
|
{
|
||||||
idx = self.base.next(state)?;
|
idx = self.base.next(state)?;
|
||||||
}
|
}
|
||||||
@ -128,10 +128,11 @@ where
|
|||||||
par as u64
|
par as u64
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#[allow(unused)]
|
||||||
pub fn new(base: CS) -> Self {
|
pub fn new(base: CS) -> Self {
|
||||||
Self {
|
Self {
|
||||||
base,
|
base,
|
||||||
skip_non_favored_prob: (DEFAULT_SKIP_NON_FAVORED_PROB * 100.0) as usize,
|
skip_non_favored_prob: DEFAULT_SKIP_NON_FAVORED_PROB,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -175,15 +176,15 @@ where
|
|||||||
/// if current_gen is empty, swap lists, sort by FavFactor, take top k and return first
|
/// if current_gen is empty, swap lists, sort by FavFactor, take top k and return first
|
||||||
fn next(&mut self, state: &mut Self::State) -> Result<CorpusId, Error> {
|
fn next(&mut self, state: &mut Self::State) -> Result<CorpusId, Error> {
|
||||||
let mut to_remove : Vec<(usize, f64)> = vec![];
|
let mut to_remove : Vec<(usize, f64)> = vec![];
|
||||||
let mut to_return : usize = 0;
|
let mut _to_return : usize = 0;
|
||||||
let corpus_len = state.corpus().count();
|
let corpus_len = state.corpus().count();
|
||||||
let mut current_len = 0;
|
let mut _current_len = 0;
|
||||||
let gm = state.metadata_map_mut().get_mut::<GeneticMetadata>().expect("Corpus Scheduler empty");
|
let gm = state.metadata_map_mut().get_mut::<GeneticMetadata>().expect("Corpus Scheduler empty");
|
||||||
// println!("index: {} curr: {:?} next: {:?} gen: {} corp: {}", gm.current_cursor, gm.current_gen.len(), gm.next_gen.len(), gm.gen,
|
// println!("index: {} curr: {:?} next: {:?} gen: {} corp: {}", gm.current_cursor, gm.current_gen.len(), gm.next_gen.len(), gm.gen,
|
||||||
// c);
|
// c);
|
||||||
match gm.current_gen.get(gm.current_cursor) {
|
match gm.current_gen.get(gm.current_cursor) {
|
||||||
Some(c) => {
|
Some(c) => {
|
||||||
current_len = gm.current_gen.len();
|
_current_len = gm.current_gen.len();
|
||||||
gm.current_cursor+=1;
|
gm.current_cursor+=1;
|
||||||
// println!("normal next: {}", (*c).0);
|
// println!("normal next: {}", (*c).0);
|
||||||
return Ok((*c).0.into())
|
return Ok((*c).0.into())
|
||||||
@ -201,25 +202,25 @@ where
|
|||||||
// for i in 0..gm.current_gen.len() {
|
// for i in 0..gm.current_gen.len() {
|
||||||
// gm.current_gen[i] = (i, gm.current_gen[i].1);
|
// gm.current_gen[i] = (i, gm.current_gen[i].1);
|
||||||
// }
|
// }
|
||||||
to_return = gm.current_gen.get(0).unwrap().0;
|
_to_return = gm.current_gen.get(0).unwrap().0;
|
||||||
// assert_eq!(to_return, 0);
|
// assert_eq!(to_return, 0);
|
||||||
gm.current_cursor=1;
|
gm.current_cursor=1;
|
||||||
gm.gen+=1;
|
gm.gen+=1;
|
||||||
current_len = gm.current_gen.len();
|
_current_len = gm.current_gen.len();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
// removing these elements will move all indices left by to_remove.len()
|
// removing these elements will move all indices left by to_remove.len()
|
||||||
// to_remove.sort_by(|x,y| x.0.cmp(&(*y).0));
|
// to_remove.sort_by(|x,y| x.0.cmp(&(*y).0));
|
||||||
// to_remove.reverse();
|
// to_remove.reverse();
|
||||||
let cm = state.corpus_mut();
|
let cm = state.corpus_mut();
|
||||||
assert_eq!(corpus_len-to_remove.len(), current_len);
|
assert_eq!(corpus_len-to_remove.len(), _current_len);
|
||||||
assert_ne!(current_len,0);
|
assert_ne!(_current_len,0);
|
||||||
for i in to_remove {
|
for i in to_remove {
|
||||||
cm.remove(i.0.into()).unwrap();
|
cm.remove(i.0.into()).unwrap();
|
||||||
}
|
}
|
||||||
assert_eq!(cm.get(to_return.into()).is_ok(),true);
|
assert_eq!(cm.get(_to_return.into()).is_ok(),true);
|
||||||
// println!("switch next: {to_return}");
|
// println!("switch next: {to_return}");
|
||||||
return Ok(to_return.into());
|
return Ok(_to_return.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add the new input to the next generation
|
/// Add the new input to the next generation
|
||||||
@ -267,6 +268,7 @@ where
|
|||||||
|
|
||||||
impl<S> GenerationScheduler<S>
|
impl<S> GenerationScheduler<S>
|
||||||
{
|
{
|
||||||
|
#[allow(unused)]
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
phantom: PhantomData,
|
phantom: PhantomData,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user