Differential observers (#868)
* reduce diffexecutor constraints for new (so it may be used in a manager-less environment) * add differential observers * finish differential observeration * requirement for observers (weak), default impl for time observer * make the map swapper, revisit how differentialobserver is implemented * semi-specialise multimap, add example * improve example slightly * fix clippy lints * fix last clippy issue * better docs + example flow * improve example: correct map sizing + multimap vs split slice * correct some comments * fix tests + slight bit more docs * fix bindings * fixups for the CI * typo fix Co-authored-by: Dominik Maier <domenukk@gmail.com> Co-authored-by: Dominik Maier <dmnk@google.com>
This commit is contained in:
parent
556789dffa
commit
0515eebbd2
1
fuzzers/baby_fuzzer_swap_differential/.gitignore
vendored
Normal file
1
fuzzers/baby_fuzzer_swap_differential/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
libpng-*
|
40
fuzzers/baby_fuzzer_swap_differential/Cargo.toml
Normal file
40
fuzzers/baby_fuzzer_swap_differential/Cargo.toml
Normal file
@ -0,0 +1,40 @@
|
||||
[package]
|
||||
name = "baby_fuzzer_swap_differential"
|
||||
version = "0.7.1"
|
||||
authors = ["Addison Crump <research@addisoncrump.info>"]
|
||||
edition = "2021"
|
||||
default-run = "fuzzer_sd"
|
||||
|
||||
[features]
|
||||
tui = []
|
||||
multimap = []
|
||||
|
||||
[profile.dev]
|
||||
panic = "abort"
|
||||
|
||||
[profile.release]
|
||||
panic = "abort"
|
||||
lto = true
|
||||
codegen-units = 1
|
||||
opt-level = 3
|
||||
debug = true
|
||||
|
||||
[build-dependencies]
|
||||
anyhow = "1"
|
||||
bindgen = "0.61"
|
||||
cc = "1.0"
|
||||
|
||||
[dependencies]
|
||||
libafl = { path = "../../libafl" }
|
||||
libafl_targets = { path = "../../libafl_targets", features = ["sancov_pcguard_hitcounts", "libfuzzer", "sancov_cmplog", "pointer_maps"] }
|
||||
mimalloc = { version = "*", default-features = false }
|
||||
|
||||
libafl_cc = { path = "../../libafl_cc/" }
|
||||
|
||||
[[bin]]
|
||||
name = "fuzzer_sd"
|
||||
path = "src/main.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "libafl_cc"
|
||||
path = "src/bin/libafl_cc.rs"
|
45
fuzzers/baby_fuzzer_swap_differential/Makefile.toml
Normal file
45
fuzzers/baby_fuzzer_swap_differential/Makefile.toml
Normal file
@ -0,0 +1,45 @@
|
||||
# Variables
|
||||
[env]
|
||||
FUZZER_NAME='fuzzer_sd'
|
||||
CARGO_TARGET_DIR = { value = "target", condition = { env_not_set = ["CARGO_TARGET_DIR"] } }
|
||||
LIBAFL_CC = '${CARGO_TARGET_DIR}/release/libafl_cc'
|
||||
FUZZER = '${CARGO_TARGET_DIR}/release/${FUZZER_NAME}'
|
||||
PROJECT_DIR = { script = ["pwd"] }
|
||||
|
||||
# Compilers
|
||||
[tasks.cc]
|
||||
command = "cargo"
|
||||
args = ["build" , "--release", "--bin", "libafl_cc"]
|
||||
|
||||
# Harness
|
||||
[tasks.fuzzer]
|
||||
command = "cargo"
|
||||
args = ["build" , "--release", "--bin", "${FUZZER_NAME}"]
|
||||
dependencies = [ "cc" ]
|
||||
|
||||
# Run the fuzzer
|
||||
[tasks.run]
|
||||
command = "${CARGO_TARGET_DIR}/release/${FUZZER_NAME}"
|
||||
dependencies = [ "fuzzer" ]
|
||||
|
||||
# Test
|
||||
[tasks.test]
|
||||
linux_alias = "test_unix"
|
||||
mac_alias = "test_unix"
|
||||
windows_alias = "unsupported"
|
||||
|
||||
[tasks.test_unix]
|
||||
script_runner = "@shell"
|
||||
script='''
|
||||
timeout 10s ${CARGO_TARGET_DIR}/release/${FUZZER_NAME}
|
||||
'''
|
||||
dependencies = [ "fuzzer" ]
|
||||
|
||||
# Clean up
|
||||
[tasks.clean]
|
||||
# Disable default `clean` definition
|
||||
clear = true
|
||||
script_runner="@shell"
|
||||
script='''
|
||||
cargo clean
|
||||
'''
|
11
fuzzers/baby_fuzzer_swap_differential/README.md
Normal file
11
fuzzers/baby_fuzzer_swap_differential/README.md
Normal file
@ -0,0 +1,11 @@
|
||||
# Baby fuzzer (swap differential)
|
||||
|
||||
This is a minimalistic example about how to create a libafl-based differential fuzzer which swaps out the AFL map during
|
||||
execution so that both maps may be measured.
|
||||
|
||||
It runs on a single core until an input is discovered which both inputs accept.
|
||||
|
||||
The tested programs are provided in `first.c` and `second.c`.
|
||||
|
||||
You may execute this fuzzer with `cargo make run`. If you prefer to do so manually, you may also simply use
|
||||
`cargo build --release --bin libafl_cc` followed by `cargo run --release --bin fuzzer_sd`
|
45
fuzzers/baby_fuzzer_swap_differential/build.rs
Normal file
45
fuzzers/baby_fuzzer_swap_differential/build.rs
Normal file
@ -0,0 +1,45 @@
|
||||
use std::{env, path::PathBuf, str::FromStr};
|
||||
|
||||
fn main() -> anyhow::Result<()> {
|
||||
if env::var("CARGO_BIN_NAME").map_or(true, |v| v != "libafl_cc") {
|
||||
println!("cargo:rerun-if-changed=./first.h");
|
||||
println!("cargo:rerun-if-changed=./first.c");
|
||||
println!("cargo:rerun-if-changed=./second.h");
|
||||
println!("cargo:rerun-if-changed=./second.c");
|
||||
println!("cargo:rerun-if-changed=./common.c");
|
||||
|
||||
// Configure and generate bindings.
|
||||
let bindings = bindgen::builder()
|
||||
.header("first.h")
|
||||
.header("second.h")
|
||||
.parse_callbacks(Box::new(bindgen::CargoCallbacks))
|
||||
.generate()?;
|
||||
|
||||
// Write the generated bindings to an output file.
|
||||
let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
|
||||
bindings
|
||||
.write_to_file(out_path.join("bindings.rs"))
|
||||
.expect("Couldn't write bindings!");
|
||||
|
||||
let compiler = env::var("CARGO_TARGET_DIR")
|
||||
.map_or(PathBuf::from_str("target").unwrap(), |v| {
|
||||
PathBuf::from_str(&v).unwrap()
|
||||
})
|
||||
.join("release/libafl_cc");
|
||||
println!("cargo:rerun-if-changed={}", compiler.to_str().unwrap());
|
||||
if !compiler.try_exists().unwrap_or(false) {
|
||||
println!("cargo:warning=Can't find libafl_cc; assuming that we're building it.");
|
||||
} else {
|
||||
cc::Build::new()
|
||||
.compiler(compiler)
|
||||
.file("first.c")
|
||||
.file("second.c")
|
||||
.file("common.c")
|
||||
.compile("diff-target");
|
||||
|
||||
println!("cargo:rustc-link-lib=diff-target");
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
12
fuzzers/baby_fuzzer_swap_differential/common.c
Normal file
12
fuzzers/baby_fuzzer_swap_differential/common.c
Normal file
@ -0,0 +1,12 @@
|
||||
#include "common.h"
|
||||
|
||||
bool both_require(const uint8_t *bytes, size_t len) {
|
||||
if (len >= 1 && bytes[0] == 'a') {
|
||||
if (len >= 2 && bytes[1] == 'b') {
|
||||
if (len >= 3 && bytes[2] == 'c') {
|
||||
return ACCEPT;
|
||||
}
|
||||
}
|
||||
}
|
||||
return REJECT;
|
||||
}
|
13
fuzzers/baby_fuzzer_swap_differential/common.h
Normal file
13
fuzzers/baby_fuzzer_swap_differential/common.h
Normal file
@ -0,0 +1,13 @@
|
||||
#ifndef LIBAFL_COMMON_H
|
||||
#define LIBAFL_COMMON_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define ACCEPT true
|
||||
#define REJECT false
|
||||
|
||||
bool both_require(const uint8_t *bytes, size_t len);
|
||||
|
||||
#endif // LIBAFL_COMMON_H
|
10
fuzzers/baby_fuzzer_swap_differential/first.c
Normal file
10
fuzzers/baby_fuzzer_swap_differential/first.c
Normal file
@ -0,0 +1,10 @@
|
||||
#include "first.h"
|
||||
|
||||
bool inspect_first(const uint8_t *bytes, size_t len) {
|
||||
if (both_require(bytes, len)) {
|
||||
if (len >= 4 && bytes[3] == 'd') {
|
||||
return ACCEPT;
|
||||
}
|
||||
}
|
||||
return REJECT;
|
||||
}
|
8
fuzzers/baby_fuzzer_swap_differential/first.h
Normal file
8
fuzzers/baby_fuzzer_swap_differential/first.h
Normal file
@ -0,0 +1,8 @@
|
||||
#ifndef LIBAFL_FIRST_H
|
||||
#define LIBAFL_FIRST_H
|
||||
|
||||
#include "common.h"
|
||||
|
||||
bool inspect_first(const uint8_t *bytes, size_t len);
|
||||
|
||||
#endif // LIBAFL_FIRST_H
|
10
fuzzers/baby_fuzzer_swap_differential/second.c
Normal file
10
fuzzers/baby_fuzzer_swap_differential/second.c
Normal file
@ -0,0 +1,10 @@
|
||||
#include "second.h"
|
||||
|
||||
bool inspect_second(const uint8_t *bytes, size_t len) {
|
||||
if (both_require(bytes, len)) {
|
||||
if (len >= 5 && bytes[4] == 'e') {
|
||||
return ACCEPT;
|
||||
}
|
||||
}
|
||||
return REJECT;
|
||||
}
|
8
fuzzers/baby_fuzzer_swap_differential/second.h
Normal file
8
fuzzers/baby_fuzzer_swap_differential/second.h
Normal file
@ -0,0 +1,8 @@
|
||||
#ifndef LIBAFL_SECOND_H
|
||||
#define LIBAFL_SECOND_H
|
||||
|
||||
#include "common.h"
|
||||
|
||||
bool inspect_second(const uint8_t *bytes, size_t len);
|
||||
|
||||
#endif // LIBAFL_SECOND_H
|
35
fuzzers/baby_fuzzer_swap_differential/src/bin/libafl_cc.rs
Normal file
35
fuzzers/baby_fuzzer_swap_differential/src/bin/libafl_cc.rs
Normal file
@ -0,0 +1,35 @@
|
||||
use std::env;
|
||||
|
||||
use libafl_cc::{ClangWrapper, CompilerWrapper};
|
||||
|
||||
pub fn main() {
|
||||
let args: Vec<String> = env::args().collect();
|
||||
if args.len() > 1 {
|
||||
let mut dir = env::current_exe().unwrap();
|
||||
let wrapper_name = dir.file_name().unwrap().to_str().unwrap();
|
||||
|
||||
let is_cpp = match wrapper_name[wrapper_name.len()-2..].to_lowercase().as_str() {
|
||||
"cc" => false,
|
||||
"++" | "pp" | "xx" => true,
|
||||
_ => panic!("Could not figure out if c or c++ wrapper was called. Expected {:?} to end with c or cxx", dir),
|
||||
};
|
||||
|
||||
dir.pop();
|
||||
|
||||
let mut cc = ClangWrapper::new();
|
||||
if let Some(code) = cc
|
||||
.cpp(is_cpp)
|
||||
// silence the compiler wrapper output, needed for some configure scripts.
|
||||
.silence(true)
|
||||
.parse_args(&args)
|
||||
.expect("Failed to parse the command line")
|
||||
.add_arg("-fsanitize-coverage=trace-pc-guard")
|
||||
.run()
|
||||
.expect("Failed to run the wrapped compiler")
|
||||
{
|
||||
std::process::exit(code);
|
||||
}
|
||||
} else {
|
||||
panic!("LibAFL CC: No Arguments given");
|
||||
}
|
||||
}
|
246
fuzzers/baby_fuzzer_swap_differential/src/main.rs
Normal file
246
fuzzers/baby_fuzzer_swap_differential/src/main.rs
Normal file
@ -0,0 +1,246 @@
|
||||
#[cfg(windows)]
|
||||
use std::ptr::write_volatile;
|
||||
use std::{
|
||||
alloc::{alloc_zeroed, Layout},
|
||||
path::PathBuf,
|
||||
};
|
||||
|
||||
#[cfg(feature = "tui")]
|
||||
use libafl::monitors::tui::TuiMonitor;
|
||||
#[cfg(not(feature = "tui"))]
|
||||
use libafl::monitors::SimpleMonitor;
|
||||
use libafl::{
|
||||
bolts::{current_nanos, rands::StdRand, tuples::tuple_list, AsSlice},
|
||||
corpus::{Corpus, InMemoryCorpus, OnDiskCorpus},
|
||||
events::SimpleEventManager,
|
||||
executors::{inprocess::InProcessExecutor, DiffExecutor, ExitKind},
|
||||
feedbacks::{CrashFeedback, MaxMapFeedback},
|
||||
fuzzer::{Fuzzer, StdFuzzer},
|
||||
generators::RandPrintablesGenerator,
|
||||
inputs::{BytesInput, HasTargetBytes},
|
||||
mutators::scheduled::{havoc_mutations, StdScheduledMutator},
|
||||
observers::StdMapObserver,
|
||||
schedulers::QueueScheduler,
|
||||
stages::mutational::StdMutationalStage,
|
||||
state::{HasSolutions, StdState},
|
||||
};
|
||||
use libafl_targets::{DifferentialAFLMapSwapObserver, MAX_EDGES_NUM};
|
||||
use mimalloc::MiMalloc;
|
||||
|
||||
#[global_allocator]
|
||||
static GLOBAL: MiMalloc = MiMalloc;
|
||||
|
||||
// bindings to the functions defined in the target
|
||||
mod bindings {
|
||||
#![allow(non_camel_case_types)]
|
||||
#![allow(non_upper_case_globals)]
|
||||
#![allow(unused)]
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
|
||||
}
|
||||
|
||||
use bindings::{inspect_first, inspect_second};
|
||||
|
||||
#[cfg(feature = "multimap")]
|
||||
mod multimap {
|
||||
pub use libafl::observers::{HitcountsIterableMapObserver, MultiMapObserver};
|
||||
|
||||
pub static mut FIRST_EDGES: &'static mut [u8] = &mut [];
|
||||
pub static mut SECOND_EDGES: &'static mut [u8] = &mut [];
|
||||
pub static mut COMBINED_EDGES: [&'static mut [u8]; 2] = [&mut [], &mut []];
|
||||
}
|
||||
#[cfg(feature = "multimap")]
|
||||
use multimap::*;
|
||||
|
||||
#[cfg(not(feature = "multimap"))]
|
||||
mod slicemap {
|
||||
pub use libafl::observers::HitcountsMapObserver;
|
||||
|
||||
pub static mut EDGES: &'static mut [u8] = &mut [];
|
||||
}
|
||||
#[cfg(not(feature = "multimap"))]
|
||||
use slicemap::*;
|
||||
|
||||
#[allow(clippy::similar_names)]
|
||||
pub fn main() {
|
||||
// The closure that we want to fuzz
|
||||
let mut first_harness = |input: &BytesInput| {
|
||||
let target = input.target_bytes();
|
||||
let buf = target.as_slice();
|
||||
if unsafe { inspect_first(buf.as_ptr(), buf.len()) } {
|
||||
ExitKind::Crash
|
||||
} else {
|
||||
ExitKind::Ok
|
||||
}
|
||||
};
|
||||
let mut second_harness = |input: &BytesInput| {
|
||||
let target = input.target_bytes();
|
||||
let buf = target.as_slice();
|
||||
if unsafe { inspect_second(buf.as_ptr(), buf.len()) } {
|
||||
ExitKind::Crash
|
||||
} else {
|
||||
ExitKind::Ok
|
||||
}
|
||||
};
|
||||
|
||||
#[cfg(feature = "multimap")]
|
||||
let (first_map_observer, second_map_observer, map_swapper, map_observer) = {
|
||||
// initialize the maps
|
||||
unsafe {
|
||||
let layout = Layout::from_size_align(MAX_EDGES_NUM, 64).unwrap();
|
||||
FIRST_EDGES = core::slice::from_raw_parts_mut(alloc_zeroed(layout), MAX_EDGES_NUM);
|
||||
SECOND_EDGES = core::slice::from_raw_parts_mut(alloc_zeroed(layout), MAX_EDGES_NUM);
|
||||
COMBINED_EDGES = [&mut FIRST_EDGES, &mut SECOND_EDGES];
|
||||
}
|
||||
|
||||
// create the base maps used to observe the different executors from two independent maps
|
||||
let mut first_map_observer = StdMapObserver::new("first-edges", unsafe { FIRST_EDGES });
|
||||
let mut second_map_observer = StdMapObserver::new("second-edges", unsafe { SECOND_EDGES });
|
||||
|
||||
// create a map swapper so that we can replace the coverage map pointer (requires feature pointer_maps!)
|
||||
let map_swapper =
|
||||
DifferentialAFLMapSwapObserver::new(&mut first_map_observer, &mut second_map_observer);
|
||||
|
||||
// create a combined map observer, e.g. for calibration
|
||||
// we use MultiMapObserver::differential to indicate that we want to use the observer in
|
||||
// differential mode
|
||||
let map_observer = HitcountsIterableMapObserver::new(MultiMapObserver::differential(
|
||||
"combined-edges",
|
||||
unsafe { &mut COMBINED_EDGES },
|
||||
));
|
||||
(
|
||||
first_map_observer,
|
||||
second_map_observer,
|
||||
map_swapper,
|
||||
map_observer,
|
||||
)
|
||||
};
|
||||
#[cfg(not(feature = "multimap"))]
|
||||
let (first_map_observer, second_map_observer, map_swapper, map_observer) = {
|
||||
// initialize the map
|
||||
unsafe {
|
||||
let layout = Layout::from_size_align(MAX_EDGES_NUM * 2, 64).unwrap();
|
||||
EDGES = core::slice::from_raw_parts_mut(alloc_zeroed(layout), MAX_EDGES_NUM * 2);
|
||||
}
|
||||
|
||||
// create the base maps used to observe the different executors by splitting a slice
|
||||
let mut first_map_observer =
|
||||
StdMapObserver::new("first-edges", unsafe { &mut EDGES[..MAX_EDGES_NUM] });
|
||||
let mut second_map_observer =
|
||||
StdMapObserver::new("second-edges", unsafe { &mut EDGES[MAX_EDGES_NUM..] });
|
||||
|
||||
// create a map swapper so that we can replace the coverage map pointer (requires feature pointer_maps!)
|
||||
let map_swapper =
|
||||
DifferentialAFLMapSwapObserver::new(&mut first_map_observer, &mut second_map_observer);
|
||||
|
||||
// create a combined map observer, e.g. for calibration
|
||||
// we use StdMapObserver::differential to indicate that we want to use the observer in
|
||||
// differential mode
|
||||
let map_observer =
|
||||
HitcountsMapObserver::new(StdMapObserver::differential("combined-edges", unsafe {
|
||||
EDGES
|
||||
}));
|
||||
(
|
||||
first_map_observer,
|
||||
second_map_observer,
|
||||
map_swapper,
|
||||
map_observer,
|
||||
)
|
||||
};
|
||||
|
||||
// Feedback to rate the interestingness of an input
|
||||
let mut feedback = MaxMapFeedback::new(&map_observer);
|
||||
|
||||
// A feedback to choose if an input is a solution or not
|
||||
// Crash here means "both crashed", which is our objective
|
||||
let mut objective = CrashFeedback::new();
|
||||
|
||||
// create a State from scratch
|
||||
let mut state = StdState::new(
|
||||
// RNG
|
||||
StdRand::with_seed(current_nanos()),
|
||||
// Corpus that will be evolved, we keep it in memory for performance
|
||||
InMemoryCorpus::new(),
|
||||
// Corpus in which we store solutions (crashes in this example),
|
||||
// on disk so the user can get them after stopping the fuzzer
|
||||
OnDiskCorpus::new(PathBuf::from("./crashes")).unwrap(),
|
||||
// States of the feedbacks.
|
||||
// The feedbacks can report the data that should persist in the State.
|
||||
&mut feedback,
|
||||
// Same for objective feedbacks
|
||||
&mut objective,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// The Monitor trait define how the fuzzer stats are displayed to the user
|
||||
#[cfg(not(feature = "tui"))]
|
||||
let mon = SimpleMonitor::new(|s| println!("{}", s));
|
||||
#[cfg(feature = "tui")]
|
||||
let mon = TuiMonitor::new(String::from("Baby Fuzzer"), false);
|
||||
|
||||
// The event manager handle the various events generated during the fuzzing loop
|
||||
// such as the notification of the addition of a new item to the corpus
|
||||
let mut mgr = SimpleEventManager::new(mon);
|
||||
|
||||
// A queue policy to get testcases from the corpus
|
||||
let scheduler = QueueScheduler::new();
|
||||
|
||||
// A fuzzer with feedbacks and a corpus scheduler
|
||||
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
|
||||
|
||||
// Create the executor for an in-process function with just one observer
|
||||
let first_executor = InProcessExecutor::new(
|
||||
&mut first_harness,
|
||||
tuple_list!(first_map_observer),
|
||||
&mut fuzzer,
|
||||
&mut state,
|
||||
&mut mgr,
|
||||
)
|
||||
.expect("Failed to create the first executor");
|
||||
let second_executor = InProcessExecutor::new(
|
||||
&mut second_harness,
|
||||
tuple_list!(second_map_observer),
|
||||
&mut fuzzer,
|
||||
&mut state,
|
||||
&mut mgr,
|
||||
)
|
||||
.expect("Failed to create the second executor");
|
||||
|
||||
// create the differential executor, providing both the map swapper (which will ensure the
|
||||
// instrumentation picks the correct map to write to) and the map observer (which provides the
|
||||
// combined feedback)
|
||||
let mut differential_executor = DiffExecutor::new(
|
||||
first_executor,
|
||||
second_executor,
|
||||
tuple_list!(map_swapper, map_observer),
|
||||
);
|
||||
|
||||
// Generator of printable bytearrays of max size 32
|
||||
let mut generator = RandPrintablesGenerator::new(32);
|
||||
|
||||
// Generate 8 initial inputs
|
||||
state
|
||||
.generate_initial_inputs(
|
||||
&mut fuzzer,
|
||||
&mut differential_executor,
|
||||
&mut generator,
|
||||
&mut mgr,
|
||||
8,
|
||||
)
|
||||
.expect("Failed to generate the initial corpus");
|
||||
|
||||
// Setup a mutational stage with a basic bytes mutator
|
||||
let mutator = StdScheduledMutator::new(havoc_mutations());
|
||||
let mut stages = tuple_list!(StdMutationalStage::new(mutator));
|
||||
|
||||
while state.solutions().is_empty() {
|
||||
fuzzer
|
||||
.fuzz_one(
|
||||
&mut stages,
|
||||
&mut differential_executor,
|
||||
&mut state,
|
||||
&mut mgr,
|
||||
)
|
||||
.expect("Error in the fuzzing loop");
|
||||
}
|
||||
}
|
@ -308,7 +308,7 @@ where
|
||||
for handle in &mut handles {
|
||||
let ecode = handle.wait()?;
|
||||
if !ecode.success() {
|
||||
println!("Client with handle {:?} exited with {:?}", handle, ecode);
|
||||
println!("Client with handle {handle:?} exited with {ecode:?}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -600,7 +600,7 @@ mod tests {
|
||||
time: _,
|
||||
executions: _,
|
||||
} => {
|
||||
let o: tuple_list_type!(StdMapObserver::<u32>) =
|
||||
let o: tuple_list_type!(StdMapObserver::<u32, false>) =
|
||||
postcard::from_bytes(observers_buf.as_ref().unwrap()).unwrap();
|
||||
assert_eq!("test", o.0.name());
|
||||
}
|
||||
|
@ -10,27 +10,28 @@ use crate::{
|
||||
bolts::{ownedref::OwnedPtrMut, tuples::MatchName},
|
||||
executors::{Executor, ExitKind, HasObservers},
|
||||
inputs::UsesInput,
|
||||
observers::{ObserversTuple, UsesObservers},
|
||||
observers::{DifferentialObserversTuple, ObserversTuple, UsesObservers},
|
||||
state::UsesState,
|
||||
Error,
|
||||
};
|
||||
|
||||
/// A [`DiffExecutor`] wraps a primary executor, forwarding its methods, and a secondary one
|
||||
#[derive(Debug)]
|
||||
pub struct DiffExecutor<A, B, OTA, OTB> {
|
||||
pub struct DiffExecutor<A, B, OTA, OTB, DOT> {
|
||||
primary: A,
|
||||
secondary: B,
|
||||
observers: UnsafeCell<ProxyObserversTuple<OTA, OTB>>,
|
||||
observers: UnsafeCell<ProxyObserversTuple<OTA, OTB, DOT>>,
|
||||
}
|
||||
|
||||
impl<A, B, OTA, OTB> DiffExecutor<A, B, OTA, OTB> {
|
||||
impl<A, B, OTA, OTB, DOT> DiffExecutor<A, B, OTA, OTB, DOT> {
|
||||
/// Create a new `DiffExecutor`, wrapping the given `executor`s.
|
||||
pub fn new<EM, Z>(primary: A, secondary: B) -> Self
|
||||
pub fn new(primary: A, secondary: B, observers: DOT) -> Self
|
||||
where
|
||||
A: Executor<EM, Z>,
|
||||
B: Executor<EM, Z, State = A::State>,
|
||||
EM: UsesState<State = A::State>,
|
||||
Z: UsesState<State = A::State>,
|
||||
A: UsesState + HasObservers<Observers = OTA>,
|
||||
B: UsesState<State = A::State> + HasObservers<Observers = OTB>,
|
||||
DOT: DifferentialObserversTuple<OTA, OTB, A::State>,
|
||||
OTA: ObserversTuple<A::State>,
|
||||
OTB: ObserversTuple<A::State>,
|
||||
{
|
||||
Self {
|
||||
primary,
|
||||
@ -38,6 +39,7 @@ impl<A, B, OTA, OTB> DiffExecutor<A, B, OTA, OTB> {
|
||||
observers: UnsafeCell::new(ProxyObserversTuple {
|
||||
primary: OwnedPtrMut::Ptr(core::ptr::null_mut()),
|
||||
secondary: OwnedPtrMut::Ptr(core::ptr::null_mut()),
|
||||
differential: observers,
|
||||
}),
|
||||
}
|
||||
}
|
||||
@ -53,13 +55,12 @@ impl<A, B, OTA, OTB> DiffExecutor<A, B, OTA, OTB> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<A, B, EM, OTA, OTB, Z> Executor<EM, Z> for DiffExecutor<A, B, OTA, OTB>
|
||||
impl<A, B, EM, DOT, Z> Executor<EM, Z> for DiffExecutor<A, B, A::Observers, B::Observers, DOT>
|
||||
where
|
||||
A: Executor<EM, Z>,
|
||||
B: Executor<EM, Z, State = A::State>,
|
||||
A: Executor<EM, Z> + HasObservers,
|
||||
B: Executor<EM, Z, State = A::State> + HasObservers,
|
||||
EM: UsesState<State = A::State>,
|
||||
OTA: Debug,
|
||||
OTB: Debug,
|
||||
DOT: DifferentialObserversTuple<A::Observers, B::Observers, A::State>,
|
||||
Z: UsesState<State = A::State>,
|
||||
{
|
||||
fn run_target(
|
||||
@ -69,10 +70,34 @@ where
|
||||
mgr: &mut EM,
|
||||
input: &Self::Input,
|
||||
) -> Result<ExitKind, Error> {
|
||||
self.observers(); // update in advance
|
||||
let observers = self.observers.get_mut();
|
||||
observers
|
||||
.differential
|
||||
.pre_observe_first_all(observers.primary.as_mut())?;
|
||||
observers.primary.as_mut().pre_exec_all(state, input)?;
|
||||
let ret1 = self.primary.run_target(fuzzer, state, mgr, input)?;
|
||||
self.primary.post_run_reset();
|
||||
observers
|
||||
.primary
|
||||
.as_mut()
|
||||
.post_exec_all(state, input, &ret1)?;
|
||||
observers
|
||||
.differential
|
||||
.post_observe_first_all(observers.primary.as_mut())?;
|
||||
observers
|
||||
.differential
|
||||
.pre_observe_second_all(observers.secondary.as_mut())?;
|
||||
observers.secondary.as_mut().pre_exec_all(state, input)?;
|
||||
let ret2 = self.secondary.run_target(fuzzer, state, mgr, input)?;
|
||||
self.secondary.post_run_reset();
|
||||
observers
|
||||
.secondary
|
||||
.as_mut()
|
||||
.post_exec_all(state, input, &ret2)?;
|
||||
observers
|
||||
.differential
|
||||
.post_observe_second_all(observers.secondary.as_mut())?;
|
||||
if ret1 == ret2 {
|
||||
Ok(ret1)
|
||||
} else {
|
||||
@ -88,22 +113,23 @@ where
|
||||
/// Proxy the observers of the inner executors
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
#[serde(
|
||||
bound = "A: serde::Serialize + serde::de::DeserializeOwned, B: serde::Serialize + serde::de::DeserializeOwned"
|
||||
bound = "A: serde::Serialize + serde::de::DeserializeOwned, B: serde::Serialize + serde::de::DeserializeOwned, DOT: serde::Serialize + serde::de::DeserializeOwned"
|
||||
)]
|
||||
pub struct ProxyObserversTuple<A, B> {
|
||||
pub struct ProxyObserversTuple<A, B, DOT> {
|
||||
primary: OwnedPtrMut<A>,
|
||||
secondary: OwnedPtrMut<B>,
|
||||
differential: DOT,
|
||||
}
|
||||
|
||||
impl<A, B, S> ObserversTuple<S> for ProxyObserversTuple<A, B>
|
||||
impl<A, B, DOT, S> ObserversTuple<S> for ProxyObserversTuple<A, B, DOT>
|
||||
where
|
||||
A: ObserversTuple<S>,
|
||||
B: ObserversTuple<S>,
|
||||
DOT: DifferentialObserversTuple<A, B, S>,
|
||||
S: UsesInput,
|
||||
{
|
||||
fn pre_exec_all(&mut self, state: &mut S, input: &S::Input) -> Result<(), Error> {
|
||||
self.primary.as_mut().pre_exec_all(state, input)?;
|
||||
self.secondary.as_mut().pre_exec_all(state, input)
|
||||
self.differential.pre_exec_all(state, input)
|
||||
}
|
||||
|
||||
fn post_exec_all(
|
||||
@ -112,17 +138,11 @@ where
|
||||
input: &S::Input,
|
||||
exit_kind: &ExitKind,
|
||||
) -> Result<(), Error> {
|
||||
self.primary
|
||||
.as_mut()
|
||||
.post_exec_all(state, input, exit_kind)?;
|
||||
self.secondary
|
||||
.as_mut()
|
||||
.post_exec_all(state, input, exit_kind)
|
||||
self.differential.post_exec_all(state, input, exit_kind)
|
||||
}
|
||||
|
||||
fn pre_exec_child_all(&mut self, state: &mut S, input: &S::Input) -> Result<(), Error> {
|
||||
self.primary.as_mut().pre_exec_child_all(state, input)?;
|
||||
self.secondary.as_mut().pre_exec_child_all(state, input)
|
||||
self.differential.pre_exec_child_all(state, input)
|
||||
}
|
||||
|
||||
fn post_exec_child_all(
|
||||
@ -131,11 +151,7 @@ where
|
||||
input: &S::Input,
|
||||
exit_kind: &ExitKind,
|
||||
) -> Result<(), Error> {
|
||||
self.primary
|
||||
.as_mut()
|
||||
.post_exec_child_all(state, input, exit_kind)?;
|
||||
self.secondary
|
||||
.as_mut()
|
||||
self.differential
|
||||
.post_exec_child_all(state, input, exit_kind)
|
||||
}
|
||||
|
||||
@ -163,43 +179,51 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<A, B> MatchName for ProxyObserversTuple<A, B>
|
||||
impl<A, B, DOT> MatchName for ProxyObserversTuple<A, B, DOT>
|
||||
where
|
||||
A: MatchName,
|
||||
B: MatchName,
|
||||
DOT: MatchName,
|
||||
{
|
||||
fn match_name<T>(&self, name: &str) -> Option<&T> {
|
||||
if let Some(t) = self.primary.as_ref().match_name::<T>(name) {
|
||||
return Some(t);
|
||||
Some(t)
|
||||
} else if let Some(t) = self.secondary.as_ref().match_name::<T>(name) {
|
||||
Some(t)
|
||||
} else {
|
||||
self.differential.match_name::<T>(name)
|
||||
}
|
||||
self.secondary.as_ref().match_name::<T>(name)
|
||||
}
|
||||
fn match_name_mut<T>(&mut self, name: &str) -> Option<&mut T> {
|
||||
if let Some(t) = self.primary.as_mut().match_name_mut::<T>(name) {
|
||||
return Some(t);
|
||||
Some(t)
|
||||
} else if let Some(t) = self.secondary.as_mut().match_name_mut::<T>(name) {
|
||||
Some(t)
|
||||
} else {
|
||||
self.differential.match_name_mut::<T>(name)
|
||||
}
|
||||
self.secondary.as_mut().match_name_mut::<T>(name)
|
||||
}
|
||||
}
|
||||
|
||||
impl<A, B> ProxyObserversTuple<A, B> {
|
||||
impl<A, B, DOT> ProxyObserversTuple<A, B, DOT> {
|
||||
fn set(&mut self, primary: &A, secondary: &B) {
|
||||
self.primary = OwnedPtrMut::Ptr(primary as *const A as *mut A);
|
||||
self.secondary = OwnedPtrMut::Ptr(secondary as *const B as *mut B);
|
||||
}
|
||||
}
|
||||
|
||||
impl<A, B, OTA, OTB> UsesObservers for DiffExecutor<A, B, OTA, OTB>
|
||||
impl<A, B, OTA, OTB, DOT> UsesObservers for DiffExecutor<A, B, OTA, OTB, DOT>
|
||||
where
|
||||
A: HasObservers<Observers = OTA>,
|
||||
B: HasObservers<Observers = OTB, State = A::State>,
|
||||
OTA: ObserversTuple<A::State>,
|
||||
OTB: ObserversTuple<A::State>,
|
||||
DOT: DifferentialObserversTuple<OTA, OTB, A::State>,
|
||||
{
|
||||
type Observers = ProxyObserversTuple<OTA, OTB>;
|
||||
type Observers = ProxyObserversTuple<OTA, OTB, DOT>;
|
||||
}
|
||||
|
||||
impl<A, B, OTA, OTB> UsesState for DiffExecutor<A, B, OTA, OTB>
|
||||
impl<A, B, OTA, OTB, DOT> UsesState for DiffExecutor<A, B, OTA, OTB, DOT>
|
||||
where
|
||||
A: UsesState,
|
||||
B: UsesState<State = A::State>,
|
||||
@ -207,15 +231,16 @@ where
|
||||
type State = A::State;
|
||||
}
|
||||
|
||||
impl<A, B, OTA, OTB> HasObservers for DiffExecutor<A, B, OTA, OTB>
|
||||
impl<A, B, OTA, OTB, DOT> HasObservers for DiffExecutor<A, B, OTA, OTB, DOT>
|
||||
where
|
||||
A: HasObservers<Observers = OTA>,
|
||||
B: HasObservers<Observers = OTB, State = A::State>,
|
||||
OTA: ObserversTuple<A::State>,
|
||||
OTB: ObserversTuple<A::State>,
|
||||
DOT: DifferentialObserversTuple<OTA, OTB, A::State>,
|
||||
{
|
||||
#[inline]
|
||||
fn observers(&self) -> &ProxyObserversTuple<OTA, OTB> {
|
||||
fn observers(&self) -> &ProxyObserversTuple<OTA, OTB, DOT> {
|
||||
unsafe {
|
||||
self.observers
|
||||
.get()
|
||||
@ -227,7 +252,7 @@ where
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn observers_mut(&mut self) -> &mut ProxyObserversTuple<OTA, OTB> {
|
||||
fn observers_mut(&mut self) -> &mut ProxyObserversTuple<OTA, OTB, DOT> {
|
||||
unsafe {
|
||||
self.observers
|
||||
.get()
|
||||
|
@ -25,7 +25,7 @@ use crate::{
|
||||
},
|
||||
executors::ExitKind,
|
||||
inputs::UsesInput,
|
||||
observers::Observer,
|
||||
observers::{DifferentialObserver, Observer, ObserversTuple},
|
||||
Error,
|
||||
};
|
||||
|
||||
@ -190,7 +190,7 @@ where
|
||||
#[derive(Clone, Serialize, Deserialize, Debug)]
|
||||
#[serde(bound = "T: serde::de::DeserializeOwned")]
|
||||
#[allow(clippy::unsafe_derive_deserialize)]
|
||||
pub struct StdMapObserver<'a, T>
|
||||
pub struct StdMapObserver<'a, T, const DIFFERENTIAL: bool>
|
||||
where
|
||||
T: Default + Copy + 'static + Serialize,
|
||||
{
|
||||
@ -199,7 +199,7 @@ where
|
||||
name: String,
|
||||
}
|
||||
|
||||
impl<'a, S, T> Observer<S> for StdMapObserver<'a, T>
|
||||
impl<'a, S, T> Observer<S> for StdMapObserver<'a, T, false>
|
||||
where
|
||||
S: UsesInput,
|
||||
T: Bounded
|
||||
@ -217,7 +217,21 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> Named for StdMapObserver<'a, T>
|
||||
impl<'a, S, T> Observer<S> for StdMapObserver<'a, T, true>
|
||||
where
|
||||
S: UsesInput,
|
||||
T: Bounded
|
||||
+ PartialEq
|
||||
+ Default
|
||||
+ Copy
|
||||
+ 'static
|
||||
+ Serialize
|
||||
+ serde::de::DeserializeOwned
|
||||
+ Debug,
|
||||
{
|
||||
}
|
||||
|
||||
impl<'a, T, const DIFFERENTIAL: bool> Named for StdMapObserver<'a, T, DIFFERENTIAL>
|
||||
where
|
||||
T: Default + Copy + 'static + Serialize + serde::de::DeserializeOwned,
|
||||
{
|
||||
@ -227,7 +241,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> HasLen for StdMapObserver<'a, T>
|
||||
impl<'a, T, const DIFFERENTIAL: bool> HasLen for StdMapObserver<'a, T, DIFFERENTIAL>
|
||||
where
|
||||
T: Default + Copy + 'static + Serialize + serde::de::DeserializeOwned,
|
||||
{
|
||||
@ -237,7 +251,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'it, T> AsIter<'it> for StdMapObserver<'a, T>
|
||||
impl<'a, 'it, T, const DIFFERENTIAL: bool> AsIter<'it> for StdMapObserver<'a, T, DIFFERENTIAL>
|
||||
where
|
||||
T: Bounded
|
||||
+ PartialEq
|
||||
@ -257,7 +271,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'it, T> AsIterMut<'it> for StdMapObserver<'a, T>
|
||||
impl<'a, 'it, T, const DIFFERENTIAL: bool> AsIterMut<'it> for StdMapObserver<'a, T, DIFFERENTIAL>
|
||||
where
|
||||
T: Bounded
|
||||
+ PartialEq
|
||||
@ -277,7 +291,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'it, T> IntoIterator for &'it StdMapObserver<'a, T>
|
||||
impl<'a, 'it, T, const DIFFERENTIAL: bool> IntoIterator for &'it StdMapObserver<'a, T, DIFFERENTIAL>
|
||||
where
|
||||
T: Bounded
|
||||
+ PartialEq
|
||||
@ -297,7 +311,8 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'it, T> IntoIterator for &'it mut StdMapObserver<'a, T>
|
||||
impl<'a, 'it, T, const DIFFERENTIAL: bool> IntoIterator
|
||||
for &'it mut StdMapObserver<'a, T, DIFFERENTIAL>
|
||||
where
|
||||
T: Bounded
|
||||
+ PartialEq
|
||||
@ -317,7 +332,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> MapObserver for StdMapObserver<'a, T>
|
||||
impl<'a, T, const DIFFERENTIAL: bool> MapObserver for StdMapObserver<'a, T, DIFFERENTIAL>
|
||||
where
|
||||
T: Bounded
|
||||
+ PartialEq
|
||||
@ -404,7 +419,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> AsSlice for StdMapObserver<'a, T>
|
||||
impl<'a, T, const DIFFERENTIAL: bool> AsSlice for StdMapObserver<'a, T, DIFFERENTIAL>
|
||||
where
|
||||
T: Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
|
||||
{
|
||||
@ -415,7 +430,7 @@ where
|
||||
self.map.as_slice()
|
||||
}
|
||||
}
|
||||
impl<'a, T> AsMutSlice for StdMapObserver<'a, T>
|
||||
impl<'a, T, const DIFFERENTIAL: bool> AsMutSlice for StdMapObserver<'a, T, DIFFERENTIAL>
|
||||
where
|
||||
T: Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
|
||||
{
|
||||
@ -427,13 +442,13 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> StdMapObserver<'a, T>
|
||||
impl<'a, T, const DIFFERENTIAL: bool> StdMapObserver<'a, T, DIFFERENTIAL>
|
||||
where
|
||||
T: Default + Copy + 'static + Serialize + serde::de::DeserializeOwned,
|
||||
{
|
||||
/// Creates a new [`MapObserver`]
|
||||
#[must_use]
|
||||
pub fn new<S>(name: S, map: &'a mut [T]) -> Self
|
||||
fn maybe_differential<S>(name: S, map: &'a mut [T]) -> Self
|
||||
where
|
||||
S: Into<String>,
|
||||
{
|
||||
@ -446,7 +461,7 @@ where
|
||||
|
||||
/// Creates a new [`MapObserver`] with an owned map
|
||||
#[must_use]
|
||||
pub fn new_owned<S>(name: S, map: Vec<T>) -> Self
|
||||
fn maybe_differential_owned<S>(name: S, map: Vec<T>) -> Self
|
||||
where
|
||||
S: Into<String>,
|
||||
{
|
||||
@ -462,7 +477,7 @@ where
|
||||
/// # Safety
|
||||
/// Will dereference the owned slice with up to len elements.
|
||||
#[must_use]
|
||||
pub fn new_from_ownedref<S>(name: S, map: OwnedSliceMut<'a, T>) -> Self
|
||||
fn maybe_differential_from_ownedref<S>(name: S, map: OwnedSliceMut<'a, T>) -> Self
|
||||
where
|
||||
S: Into<String>,
|
||||
{
|
||||
@ -477,7 +492,7 @@ where
|
||||
///
|
||||
/// # Safety
|
||||
/// Will dereference the `map_ptr` with up to len elements.
|
||||
pub unsafe fn new_from_ptr<S>(name: S, map_ptr: *mut T, len: usize) -> Self
|
||||
unsafe fn maybe_differential_from_ptr<S>(name: S, map_ptr: *mut T, len: usize) -> Self
|
||||
where
|
||||
S: Into<String>,
|
||||
{
|
||||
@ -487,6 +502,124 @@ where
|
||||
initial: T::default(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets the backing for this map
|
||||
pub fn map(&self) -> &OwnedSliceMut<'a, T> {
|
||||
&self.map
|
||||
}
|
||||
|
||||
/// Gets the backing for this map mutably
|
||||
pub fn map_mut(&mut self) -> &mut OwnedSliceMut<'a, T> {
|
||||
&mut self.map
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> StdMapObserver<'a, T, false>
|
||||
where
|
||||
T: Default + Copy + 'static + Serialize + serde::de::DeserializeOwned,
|
||||
{
|
||||
/// Creates a new [`MapObserver`]
|
||||
#[must_use]
|
||||
pub fn new<S>(name: S, map: &'a mut [T]) -> Self
|
||||
where
|
||||
S: Into<String>,
|
||||
{
|
||||
Self::maybe_differential(name, map)
|
||||
}
|
||||
|
||||
/// Creates a new [`MapObserver`] with an owned map
|
||||
#[must_use]
|
||||
pub fn new_owned<S>(name: S, map: Vec<T>) -> Self
|
||||
where
|
||||
S: Into<String>,
|
||||
{
|
||||
Self::maybe_differential_owned(name, map)
|
||||
}
|
||||
|
||||
/// Creates a new [`MapObserver`] from an [`OwnedSliceMut`] map.
|
||||
///
|
||||
/// # Safety
|
||||
/// Will dereference the owned slice with up to len elements.
|
||||
#[must_use]
|
||||
pub fn new_from_ownedref<S>(name: S, map: OwnedSliceMut<'a, T>) -> Self
|
||||
where
|
||||
S: Into<String>,
|
||||
{
|
||||
Self::maybe_differential_from_ownedref(name, map)
|
||||
}
|
||||
|
||||
/// Creates a new [`MapObserver`] from a raw pointer
|
||||
///
|
||||
/// # Safety
|
||||
/// Will dereference the `map_ptr` with up to len elements.
|
||||
pub unsafe fn new_from_ptr<S>(name: S, map_ptr: *mut T, len: usize) -> Self
|
||||
where
|
||||
S: Into<String>,
|
||||
{
|
||||
Self::maybe_differential_from_ptr(name, map_ptr, len)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> StdMapObserver<'a, T, true>
|
||||
where
|
||||
T: Default + Copy + 'static + Serialize + serde::de::DeserializeOwned,
|
||||
{
|
||||
/// Creates a new [`MapObserver`] in differential mode
|
||||
#[must_use]
|
||||
pub fn differential<S>(name: S, map: &'a mut [T]) -> Self
|
||||
where
|
||||
S: Into<String>,
|
||||
{
|
||||
Self::maybe_differential(name, map)
|
||||
}
|
||||
|
||||
/// Creates a new [`MapObserver`] with an owned map in differential mode
|
||||
#[must_use]
|
||||
pub fn differential_owned<S>(name: S, map: Vec<T>) -> Self
|
||||
where
|
||||
S: Into<String>,
|
||||
{
|
||||
Self::maybe_differential_owned(name, map)
|
||||
}
|
||||
|
||||
/// Creates a new [`MapObserver`] from an [`OwnedSliceMut`] map in differential mode.
|
||||
///
|
||||
/// # Safety
|
||||
/// Will dereference the owned slice with up to len elements.
|
||||
#[must_use]
|
||||
pub fn differential_from_ownedref<S>(name: S, map: OwnedSliceMut<'a, T>) -> Self
|
||||
where
|
||||
S: Into<String>,
|
||||
{
|
||||
Self::maybe_differential_from_ownedref(name, map)
|
||||
}
|
||||
|
||||
/// Creates a new [`MapObserver`] from a raw pointer in differential mode
|
||||
///
|
||||
/// # Safety
|
||||
/// Will dereference the `map_ptr` with up to len elements.
|
||||
pub unsafe fn differential_from_ptr<S>(name: S, map_ptr: *mut T, len: usize) -> Self
|
||||
where
|
||||
S: Into<String>,
|
||||
{
|
||||
Self::maybe_differential_from_ptr(name, map_ptr, len)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, OTA, OTB, S, T> DifferentialObserver<OTA, OTB, S> for StdMapObserver<'a, T, true>
|
||||
where
|
||||
OTA: ObserversTuple<S>,
|
||||
OTB: ObserversTuple<S>,
|
||||
S: UsesInput,
|
||||
T: Bounded
|
||||
+ PartialEq
|
||||
+ Default
|
||||
+ Copy
|
||||
+ 'static
|
||||
+ Serialize
|
||||
+ serde::de::DeserializeOwned
|
||||
+ Debug,
|
||||
{
|
||||
}
|
||||
|
||||
/// Use a const size to speedup `Feedback::is_interesting` when the user can
|
||||
@ -1171,6 +1304,7 @@ where
|
||||
self.base.as_slice()
|
||||
}
|
||||
}
|
||||
|
||||
impl<M> AsMutSlice for HitcountsMapObserver<M>
|
||||
where
|
||||
M: MapObserver + AsMutSlice,
|
||||
@ -1243,6 +1377,33 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<M, OTA, OTB, S> DifferentialObserver<OTA, OTB, S> for HitcountsMapObserver<M>
|
||||
where
|
||||
M: DifferentialObserver<OTA, OTB, S>
|
||||
+ MapObserver<Entry = u8>
|
||||
+ Serialize
|
||||
+ AsMutSlice<Entry = u8>,
|
||||
OTA: ObserversTuple<S>,
|
||||
OTB: ObserversTuple<S>,
|
||||
S: UsesInput,
|
||||
{
|
||||
fn pre_observe_first(&mut self, observers: &mut OTA) -> Result<(), Error> {
|
||||
self.base.pre_observe_first(observers)
|
||||
}
|
||||
|
||||
fn post_observe_first(&mut self, observers: &mut OTA) -> Result<(), Error> {
|
||||
self.base.post_observe_first(observers)
|
||||
}
|
||||
|
||||
fn pre_observe_second(&mut self, observers: &mut OTB) -> Result<(), Error> {
|
||||
self.base.pre_observe_second(observers)
|
||||
}
|
||||
|
||||
fn post_observe_second(&mut self, observers: &mut OTB) -> Result<(), Error> {
|
||||
self.base.post_observe_second(observers)
|
||||
}
|
||||
}
|
||||
|
||||
/// Map observer with hitcounts postprocessing
|
||||
/// Less optimized version for non-slice iterators.
|
||||
/// Slice-backed observers should use a [`HitcountsMapObserver`].
|
||||
@ -1439,11 +1600,36 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<M, OTA, OTB, S> DifferentialObserver<OTA, OTB, S> for HitcountsIterableMapObserver<M>
|
||||
where
|
||||
M: MapObserver<Entry = u8> + Observer<S> + DifferentialObserver<OTA, OTB, S>,
|
||||
for<'it> M: AsIterMut<'it, Item = u8>,
|
||||
OTA: ObserversTuple<S>,
|
||||
OTB: ObserversTuple<S>,
|
||||
S: UsesInput,
|
||||
{
|
||||
fn pre_observe_first(&mut self, observers: &mut OTA) -> Result<(), Error> {
|
||||
self.base.pre_observe_first(observers)
|
||||
}
|
||||
|
||||
fn post_observe_first(&mut self, observers: &mut OTA) -> Result<(), Error> {
|
||||
self.base.post_observe_first(observers)
|
||||
}
|
||||
|
||||
fn pre_observe_second(&mut self, observers: &mut OTB) -> Result<(), Error> {
|
||||
self.base.pre_observe_second(observers)
|
||||
}
|
||||
|
||||
fn post_observe_second(&mut self, observers: &mut OTB) -> Result<(), Error> {
|
||||
self.base.post_observe_second(observers)
|
||||
}
|
||||
}
|
||||
|
||||
/// The Multi Map Observer merge different maps into one observer
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
#[serde(bound = "T: serde::de::DeserializeOwned")]
|
||||
#[allow(clippy::unsafe_derive_deserialize)]
|
||||
pub struct MultiMapObserver<'a, T>
|
||||
pub struct MultiMapObserver<'a, T, const DIFFERENTIAL: bool>
|
||||
where
|
||||
T: Default + Copy + 'static + Serialize + Debug,
|
||||
{
|
||||
@ -1455,7 +1641,7 @@ where
|
||||
iter_idx: usize,
|
||||
}
|
||||
|
||||
impl<'a, S, T> Observer<S> for MultiMapObserver<'a, T>
|
||||
impl<'a, S, T> Observer<S> for MultiMapObserver<'a, T, false>
|
||||
where
|
||||
S: UsesInput,
|
||||
T: Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
|
||||
@ -1467,7 +1653,16 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> Named for MultiMapObserver<'a, T>
|
||||
impl<'a, S, T> Observer<S> for MultiMapObserver<'a, T, true>
|
||||
where
|
||||
S: UsesInput,
|
||||
T: Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
|
||||
Self: MapObserver,
|
||||
{
|
||||
// in differential mode, we are *not* responsible for resetting the map!
|
||||
}
|
||||
|
||||
impl<'a, T, const DIFFERENTIAL: bool> Named for MultiMapObserver<'a, T, DIFFERENTIAL>
|
||||
where
|
||||
T: Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
|
||||
{
|
||||
@ -1477,7 +1672,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> HasLen for MultiMapObserver<'a, T>
|
||||
impl<'a, T, const DIFFERENTIAL: bool> HasLen for MultiMapObserver<'a, T, DIFFERENTIAL>
|
||||
where
|
||||
T: Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
|
||||
{
|
||||
@ -1487,7 +1682,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> MapObserver for MultiMapObserver<'a, T>
|
||||
impl<'a, T, const DIFFERENTIAL: bool> MapObserver for MultiMapObserver<'a, T, DIFFERENTIAL>
|
||||
where
|
||||
T: Bounded
|
||||
+ PartialEq
|
||||
@ -1589,13 +1784,13 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> MultiMapObserver<'a, T>
|
||||
impl<'a, T, const DIFFERENTIAL: bool> MultiMapObserver<'a, T, DIFFERENTIAL>
|
||||
where
|
||||
T: Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
|
||||
{
|
||||
/// Creates a new [`MultiMapObserver`]
|
||||
/// Creates a new [`MultiMapObserver`], maybe in differential mode
|
||||
#[must_use]
|
||||
pub fn new(name: &'static str, maps: &'a mut [&'a mut [T]]) -> Self {
|
||||
fn new_maybe_differential(name: &'static str, maps: &'a mut [&'a mut [T]]) -> Self {
|
||||
let mut idx = 0;
|
||||
let mut v = 0;
|
||||
let mut builder = vec![];
|
||||
@ -1619,6 +1814,28 @@ where
|
||||
iter_idx: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> MultiMapObserver<'a, T, true>
|
||||
where
|
||||
T: Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
|
||||
{
|
||||
/// Creates a new [`MultiMapObserver`] in differential mode
|
||||
#[must_use]
|
||||
pub fn differential(name: &'static str, maps: &'a mut [&'a mut [T]]) -> Self {
|
||||
Self::new_maybe_differential(name, maps)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> MultiMapObserver<'a, T, false>
|
||||
where
|
||||
T: Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
|
||||
{
|
||||
/// Creates a new [`MultiMapObserver`]
|
||||
#[must_use]
|
||||
pub fn new(name: &'static str, maps: &'a mut [&'a mut [T]]) -> Self {
|
||||
Self::new_maybe_differential(name, maps)
|
||||
}
|
||||
|
||||
/// Creates a new [`MultiMapObserver`] with an owned map
|
||||
#[must_use]
|
||||
@ -1648,7 +1865,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'it, T> AsIter<'it> for MultiMapObserver<'a, T>
|
||||
impl<'a, 'it, T, const DIFFERENTIAL: bool> AsIter<'it> for MultiMapObserver<'a, T, DIFFERENTIAL>
|
||||
where
|
||||
T: Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
|
||||
'a: 'it,
|
||||
@ -1661,7 +1878,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'it, T> AsIterMut<'it> for MultiMapObserver<'a, T>
|
||||
impl<'a, 'it, T, const DIFFERENTIAL: bool> AsIterMut<'it> for MultiMapObserver<'a, T, DIFFERENTIAL>
|
||||
where
|
||||
T: Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
|
||||
'a: 'it,
|
||||
@ -1674,7 +1891,8 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'it, T> IntoIterator for &'it MultiMapObserver<'a, T>
|
||||
impl<'a, 'it, T, const DIFFERENTIAL: bool> IntoIterator
|
||||
for &'it MultiMapObserver<'a, T, DIFFERENTIAL>
|
||||
where
|
||||
T: Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
|
||||
{
|
||||
@ -1686,7 +1904,8 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'it, T> IntoIterator for &'it mut MultiMapObserver<'a, T>
|
||||
impl<'a, 'it, T, const DIFFERENTIAL: bool> IntoIterator
|
||||
for &'it mut MultiMapObserver<'a, T, DIFFERENTIAL>
|
||||
where
|
||||
T: Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
|
||||
{
|
||||
@ -1698,6 +1917,16 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T, OTA, OTB, S> DifferentialObserver<OTA, OTB, S> for MultiMapObserver<'a, T, true>
|
||||
where
|
||||
T: Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
|
||||
Self: MapObserver,
|
||||
OTA: ObserversTuple<S>,
|
||||
OTB: ObserversTuple<S>,
|
||||
S: UsesInput,
|
||||
{
|
||||
}
|
||||
|
||||
/// Exact copy of `StdMapObserver` that owns its map
|
||||
/// Used for python bindings
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
@ -1894,6 +2123,7 @@ where
|
||||
self.map.as_slice()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> AsMutSlice for OwnedMapObserver<T>
|
||||
where
|
||||
T: Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
|
||||
@ -1987,7 +2217,7 @@ pub mod pybind {
|
||||
/// Python class for StdMapObserver
|
||||
pub struct $struct_name1 {
|
||||
/// Rust wrapped StdMapObserver object
|
||||
pub inner: StdMapObserver<'static, $datatype>,
|
||||
pub inner: StdMapObserver<'static, $datatype, false>,
|
||||
}
|
||||
|
||||
#[pymethods]
|
||||
|
@ -286,6 +286,130 @@ pub trait ObserverWithHashField {
|
||||
fn clear_hash(&mut self);
|
||||
}
|
||||
|
||||
/// A trait for [`Observer`]`s` which observe over differential execution.
|
||||
///
|
||||
/// Differential observers have the following flow during a single execution:
|
||||
/// - `Observer::pre_exec` for the differential observer is invoked.
|
||||
/// - `DifferentialObserver::pre_observe_first` for the differential observer is invoked.
|
||||
/// - `Observer::pre_exec` for each of the observers for the first executor is invoked.
|
||||
/// - The first executor is invoked.
|
||||
/// - `Observer::post_exec` for each of the observers for the first executor is invoked.
|
||||
/// - `DifferentialObserver::post_observe_first` for the differential observer is invoked.
|
||||
/// - `DifferentialObserver::pre_observe_second` for the differential observer is invoked.
|
||||
/// - `Observer::pre_exec` for each of the observers for the second executor is invoked.
|
||||
/// - The second executor is invoked.
|
||||
/// - `Observer::post_exec` for each of the observers for the second executor is invoked.
|
||||
/// - `DifferentialObserver::post_observe_second` for the differential observer is invoked.
|
||||
/// - `Observer::post_exec` for the differential observer is invoked.
|
||||
///
|
||||
/// You should perform any preparation for the diff execution in `Observer::pre_exec` and respective
|
||||
/// cleanup in `Observer::post_exec`. For individual executions, use
|
||||
/// `DifferentialObserver::{pre,post}_observe_{first,second}` as necessary for first and second,
|
||||
/// respectively.
|
||||
#[allow(unused_variables)]
|
||||
pub trait DifferentialObserver<OTA, OTB, S>: Observer<S>
|
||||
where
|
||||
OTA: ObserversTuple<S>,
|
||||
OTB: ObserversTuple<S>,
|
||||
S: UsesInput,
|
||||
{
|
||||
/// Perform an operation with the first set of observers before they are `pre_exec`'d.
|
||||
fn pre_observe_first(&mut self, observers: &mut OTA) -> Result<(), Error> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Perform an operation with the first set of observers after they are `post_exec`'d.
|
||||
fn post_observe_first(&mut self, observers: &mut OTA) -> Result<(), Error> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Perform an operation with the second set of observers before they are `pre_exec`'d.
|
||||
fn pre_observe_second(&mut self, observers: &mut OTB) -> Result<(), Error> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Perform an operation with the second set of observers after they are `post_exec`'d.
|
||||
fn post_observe_second(&mut self, observers: &mut OTB) -> Result<(), Error> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Differential observers tuple, for when you're using multiple differential observers.
|
||||
pub trait DifferentialObserversTuple<OTA, OTB, S>: ObserversTuple<S>
|
||||
where
|
||||
OTA: ObserversTuple<S>,
|
||||
OTB: ObserversTuple<S>,
|
||||
S: UsesInput,
|
||||
{
|
||||
/// Perform an operation with the first set of observers before they are `pre_exec`'d on all the
|
||||
/// differential observers in this tuple.
|
||||
fn pre_observe_first_all(&mut self, observers: &mut OTA) -> Result<(), Error>;
|
||||
|
||||
/// Perform an operation with the first set of observers after they are `post_exec`'d on all the
|
||||
/// differential observers in this tuple.
|
||||
fn post_observe_first_all(&mut self, observers: &mut OTA) -> Result<(), Error>;
|
||||
|
||||
/// Perform an operation with the second set of observers before they are `pre_exec`'d on all
|
||||
/// the differential observers in this tuple.
|
||||
fn pre_observe_second_all(&mut self, observers: &mut OTB) -> Result<(), Error>;
|
||||
|
||||
/// Perform an operation with the second set of observers after they are `post_exec`'d on all
|
||||
/// the differential observers in this tuple.
|
||||
fn post_observe_second_all(&mut self, observers: &mut OTB) -> Result<(), Error>;
|
||||
}
|
||||
|
||||
impl<OTA, OTB, S> DifferentialObserversTuple<OTA, OTB, S> for ()
|
||||
where
|
||||
OTA: ObserversTuple<S>,
|
||||
OTB: ObserversTuple<S>,
|
||||
S: UsesInput,
|
||||
{
|
||||
fn pre_observe_first_all(&mut self, _: &mut OTA) -> Result<(), Error> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn post_observe_first_all(&mut self, _: &mut OTA) -> Result<(), Error> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn pre_observe_second_all(&mut self, _: &mut OTB) -> Result<(), Error> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn post_observe_second_all(&mut self, _: &mut OTB) -> Result<(), Error> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<Head, Tail, OTA, OTB, S> DifferentialObserversTuple<OTA, OTB, S> for (Head, Tail)
|
||||
where
|
||||
Head: DifferentialObserver<OTA, OTB, S>,
|
||||
Tail: DifferentialObserversTuple<OTA, OTB, S>,
|
||||
OTA: ObserversTuple<S>,
|
||||
OTB: ObserversTuple<S>,
|
||||
S: UsesInput,
|
||||
{
|
||||
fn pre_observe_first_all(&mut self, observers: &mut OTA) -> Result<(), Error> {
|
||||
self.0.pre_observe_first(observers)?;
|
||||
self.1.pre_observe_first_all(observers)
|
||||
}
|
||||
|
||||
fn post_observe_first_all(&mut self, observers: &mut OTA) -> Result<(), Error> {
|
||||
self.0.post_observe_first(observers)?;
|
||||
self.1.post_observe_first_all(observers)
|
||||
}
|
||||
|
||||
fn pre_observe_second_all(&mut self, observers: &mut OTB) -> Result<(), Error> {
|
||||
self.0.pre_observe_second(observers)?;
|
||||
self.1.pre_observe_second_all(observers)
|
||||
}
|
||||
|
||||
fn post_observe_second_all(&mut self, observers: &mut OTB) -> Result<(), Error> {
|
||||
self.0.post_observe_second(observers)?;
|
||||
self.1.post_observe_second_all(observers)
|
||||
}
|
||||
}
|
||||
|
||||
/// A simple observer, just overlooking the runtime of the target.
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub struct TimeObserver {
|
||||
@ -339,6 +463,14 @@ impl Named for TimeObserver {
|
||||
}
|
||||
}
|
||||
|
||||
impl<OTA, OTB, S> DifferentialObserver<OTA, OTB, S> for TimeObserver
|
||||
where
|
||||
OTA: ObserversTuple<S>,
|
||||
OTB: ObserversTuple<S>,
|
||||
S: UsesInput,
|
||||
{
|
||||
}
|
||||
|
||||
/// A simple observer with a list of things.
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
#[serde(bound = "T: serde::de::DeserializeOwned")]
|
||||
@ -1204,7 +1336,7 @@ mod tests {
|
||||
);
|
||||
let vec = postcard::to_allocvec(&obv).unwrap();
|
||||
println!("{vec:?}");
|
||||
let obv2: tuple_list_type!(TimeObserver, StdMapObserver<u32>) =
|
||||
let obv2: tuple_list_type!(TimeObserver, StdMapObserver<u32, false>) =
|
||||
postcard::from_bytes(&vec).unwrap();
|
||||
assert_eq!(obv.0.name(), obv2.0.name());
|
||||
}
|
||||
|
@ -89,3 +89,115 @@ pub fn edges_max_num() -> usize {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "pointer_maps")]
|
||||
pub use swap::*;
|
||||
|
||||
#[cfg(feature = "pointer_maps")]
|
||||
mod swap {
|
||||
use alloc::string::{String, ToString};
|
||||
use core::fmt::Debug;
|
||||
|
||||
use libafl::{
|
||||
bolts::{ownedref::OwnedSliceMut, tuples::Named, AsMutSlice},
|
||||
inputs::UsesInput,
|
||||
observers::{DifferentialObserver, Observer, ObserversTuple, StdMapObserver},
|
||||
Error,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use super::{EDGES_MAP_PTR, EDGES_MAP_PTR_SIZE};
|
||||
|
||||
/// Observer to be used with `DiffExecutor`s when executing a differential target that shares
|
||||
/// the AFL map in order to swap out the maps (and thus allow for map observing the two targets
|
||||
/// separately).
|
||||
#[allow(clippy::unsafe_derive_deserialize)]
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct DifferentialAFLMapSwapObserver<'a, 'b> {
|
||||
first_map: OwnedSliceMut<'a, u8>,
|
||||
second_map: OwnedSliceMut<'b, u8>,
|
||||
first_name: String,
|
||||
second_name: String,
|
||||
name: String,
|
||||
}
|
||||
|
||||
impl<'a, 'b> DifferentialAFLMapSwapObserver<'a, 'b> {
|
||||
/// Create a new `DifferentialAFLMapSwapObserver`.
|
||||
pub fn new<const D1: bool, const D2: bool>(
|
||||
first: &mut StdMapObserver<'a, u8, D1>,
|
||||
second: &mut StdMapObserver<'b, u8, D2>,
|
||||
) -> Self {
|
||||
Self {
|
||||
first_name: first.name().to_string(),
|
||||
second_name: second.name().to_string(),
|
||||
name: format!("differential_{}_{}", first.name(), second.name()),
|
||||
first_map: unsafe {
|
||||
let slice = first.map_mut().as_mut_slice();
|
||||
OwnedSliceMut::from_raw_parts_mut(slice.as_mut_ptr(), slice.len())
|
||||
},
|
||||
second_map: unsafe {
|
||||
let slice = second.map_mut().as_mut_slice();
|
||||
OwnedSliceMut::from_raw_parts_mut(slice.as_mut_ptr(), slice.len())
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the first map
|
||||
#[must_use]
|
||||
pub fn first_map(&self) -> &OwnedSliceMut<'a, u8> {
|
||||
&self.first_map
|
||||
}
|
||||
|
||||
/// Get the second map
|
||||
#[must_use]
|
||||
pub fn second_map(&self) -> &OwnedSliceMut<'b, u8> {
|
||||
&self.second_map
|
||||
}
|
||||
|
||||
/// Get the first name
|
||||
#[must_use]
|
||||
pub fn first_name(&self) -> &str {
|
||||
&self.first_name
|
||||
}
|
||||
|
||||
/// Get the second name
|
||||
#[must_use]
|
||||
pub fn second_name(&self) -> &str {
|
||||
&self.second_name
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b> Named for DifferentialAFLMapSwapObserver<'a, 'b> {
|
||||
fn name(&self) -> &str {
|
||||
&self.name
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b, S> Observer<S> for DifferentialAFLMapSwapObserver<'a, 'b> where S: UsesInput {}
|
||||
|
||||
impl<'a, 'b, OTA, OTB, S> DifferentialObserver<OTA, OTB, S>
|
||||
for DifferentialAFLMapSwapObserver<'a, 'b>
|
||||
where
|
||||
OTA: ObserversTuple<S>,
|
||||
OTB: ObserversTuple<S>,
|
||||
S: UsesInput,
|
||||
{
|
||||
fn pre_observe_first(&mut self, _: &mut OTA) -> Result<(), Error> {
|
||||
let slice = self.first_map.as_mut_slice();
|
||||
unsafe {
|
||||
EDGES_MAP_PTR = slice.as_mut_ptr();
|
||||
EDGES_MAP_PTR_SIZE = slice.len();
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn pre_observe_second(&mut self, _: &mut OTB) -> Result<(), Error> {
|
||||
let slice = self.second_map.as_mut_slice();
|
||||
unsafe {
|
||||
EDGES_MAP_PTR = slice.as_mut_ptr();
|
||||
EDGES_MAP_PTR_SIZE = slice.len();
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user