Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

libafl-fuzz: separate frida build + cmplog debug #2591

Merged
merged 77 commits into from
Oct 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
77 commits
Select commit Hold shift + click to select a range
0bd362c
libafl-fuzz: separate frida build
R9295 Oct 8, 2024
a8cfc84
cmplog debug
R9295 Oct 8, 2024
66245dc
update
R9295 Oct 8, 2024
8d3f5f6
merge AflStatsStage
R9295 Oct 8, 2024
9d1a98d
mandate track_hit_feedbacks feature for AflStatsStage
R9295 Oct 8, 2024
012ab10
afl_stats do not hardcode TimeoutFeedback and CrashFeedback names
R9295 Oct 8, 2024
6534c94
typo
R9295 Oct 8, 2024
18f1fed
typo
R9295 Oct 8, 2024
02f85d9
fix generics order
R9295 Oct 9, 2024
6a358e8
add verify timeouts stage
R9295 Oct 9, 2024
def8485
libafl: introduce set_timeout func to dynamically set timeouts for ex…
R9295 Oct 9, 2024
a3f203e
add missing set_timeout implementations
R9295 Oct 10, 2024
eec5505
libafl-fuzz: move set_timeout and timeout from Executor to HasTimeout
R9295 Oct 11, 2024
d17f50a
libafl-fuzz: add removed gitignore
R9295 Oct 11, 2024
2a35f55
remove timeout from libafl_nyx::Executor and move it to NyxHelper
R9295 Oct 11, 2024
74e41c7
clippy
R9295 Oct 11, 2024
57e8417
Merge branch 'main' into libafl-fuzz/frida-mode-separate
R9295 Oct 11, 2024
282514b
fix HasTimeout for QemuExecutor
R9295 Oct 11, 2024
5b24eac
libafl-fuzz: remove observer handle usage in verify_timeouts
R9295 Oct 11, 2024
2eab13c
libafl-fuzz: fix foreign_sync_dirs option
R9295 Oct 11, 2024
27d3e78
Merge branch 'main' into libafl-fuzz/frida-mode-separate
R9295 Oct 14, 2024
1c5a5eb
fmt && clippy
R9295 Oct 14, 2024
5ee0216
clippy && fmt
R9295 Oct 14, 2024
c04a779
missing doc
R9295 Oct 14, 2024
866cbce
clippy
R9295 Oct 14, 2024
03cae63
bruh
R9295 Oct 14, 2024
0ffb0a7
damned doc build
R9295 Oct 14, 2024
5f79ecd
trait fix
R9295 Oct 14, 2024
22db281
impl HasTimeout for InProcessExecutor only if std
R9295 Oct 14, 2024
c5edce4
clippy
R9295 Oct 14, 2024
dcb1774
fix typo
R9295 Oct 15, 2024
c4ce299
fix nostd build
R9295 Oct 15, 2024
97b6792
clippy
R9295 Oct 15, 2024
8662e7b
remove most HasTimeout implementations for now
R9295 Oct 15, 2024
1b82afb
typo
R9295 Oct 15, 2024
bd46c24
remove redundant import
R9295 Oct 15, 2024
084f1d5
misc
R9295 Oct 15, 2024
c83caa8
fmt
R9295 Oct 15, 2024
b94613d
simplify trait bounds
R9295 Oct 22, 2024
5a41359
add old AflStatsStage back and rename it to StatsStage
R9295 Oct 22, 2024
5eb82b5
fix ci
R9295 Oct 22, 2024
049a940
make set_timeout and timeout of HasTimeout inline
R9295 Oct 22, 2024
fbad346
fmt
R9295 Oct 22, 2024
55851c9
add gitignore
R9295 Oct 22, 2024
3ce8a08
serde_any fix
R9295 Oct 22, 2024
00e5bab
tmate
R9295 Oct 22, 2024
9e3f66d
misc
R9295 Oct 22, 2024
dcb2f81
remove tmate
R9295 Oct 22, 2024
4344350
test
R9295 Oct 22, 2024
0860235
coordinate between capture_timeout and verify_timeout
R9295 Oct 22, 2024
f43f37b
makefile
R9295 Oct 22, 2024
6de0332
fix
R9295 Oct 22, 2024
be31f5e
fix
R9295 Oct 22, 2024
1f0e96e
fmt
R9295 Oct 22, 2024
8c19f6e
increase cmplog timeout
R9295 Oct 22, 2024
59bddef
semantic
R9295 Oct 22, 2024
f25747e
debug
R9295 Oct 23, 2024
46ae082
debug
R9295 Oct 23, 2024
527e310
remove dbeug
R9295 Oct 23, 2024
a1e7e77
only test libafl-fuzz on CI for now
R9295 Oct 24, 2024
d50ea37
better seed for cmplog?
R9295 Oct 24, 2024
17fcb49
Merge remote-tracking branch 'origin/main' into libafl-fuzz/frida-mod…
R9295 Oct 24, 2024
e722eb0
remove preflight check for now
R9295 Oct 24, 2024
2b14512
set Input type in forkserver
R9295 Oct 24, 2024
4cb3715
debug
R9295 Oct 24, 2024
2b3cbbb
tmate
R9295 Oct 24, 2024
99ffca3
fix capture_timeout
R9295 Oct 24, 2024
4c0b388
revert workflow
R9295 Oct 24, 2024
8ad5342
run only libafl-fuzz
R9295 Oct 24, 2024
ac0d38b
remove pre-flight
R9295 Oct 24, 2024
6401708
Merge branch 'main' into libafl-fuzz/frida-mode-separate
domenukk Oct 25, 2024
6c115f9
re-enable fuzzers on CI
R9295 Oct 28, 2024
1c99e0c
move capture_timeouts and verify_timeouts to main lib
R9295 Oct 28, 2024
3b858bf
run fmt
R9295 Oct 28, 2024
9b95476
add note for verify timeouts
R9295 Oct 28, 2024
4135ab8
add note in verify timeouts stage
R9295 Oct 28, 2024
bc0f70d
typo
R9295 Oct 28, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions fuzzers/baby/backtrace_baby_fuzzers/command_executor/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ pub fn main() {
#[derive(Debug)]
struct MyExecutor {
shmem_id: ShMemId,
timeout: Duration,
}

impl CommandConfigurator<BytesInput> for MyExecutor {
Expand All @@ -106,11 +107,16 @@ pub fn main() {
}

fn exec_timeout(&self) -> Duration {
Duration::from_secs(5)
self.timeout
}
fn exec_timeout_mut(&mut self) -> &mut Duration {
&mut self.timeout
}
}

let mut executor = MyExecutor { shmem_id }.into_executor(tuple_list!(observer, bt_observer));
let timeout = Duration::from_secs(5);
let mut executor =
MyExecutor { shmem_id, timeout }.into_executor(tuple_list!(observer, bt_observer));

// Generator of printable bytearrays of max size 32
let mut generator = RandPrintablesGenerator::new(nonzero!(32));
Expand Down
2 changes: 1 addition & 1 deletion fuzzers/binary_only/frida_libpng/harness_win.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
#include <string.h>

extern "C" __declspec(dllexport) size_t
LLVMFuzzerTestOneInput(const char *data, unsigned int len) {
LLVMFuzzerTestOneInput(const char *data, unsigned int len) {
if (data[0] == 'b') {
if (data[1] == 'a') {
if (data[2] == 'd') {
Expand Down
6 changes: 3 additions & 3 deletions fuzzers/binary_only/qemu_launcher/src/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ use libafl::{
powersched::PowerSchedule, IndexesLenTimeMinimizerScheduler, PowerQueueScheduler,
},
stages::{
calibrate::CalibrationStage, power::StdPowerMutationalStage, AflStatsStage, IfStage,
ShadowTracingStage, StagesTuple, StdMutationalStage,
calibrate::CalibrationStage, power::StdPowerMutationalStage, IfStage, ShadowTracingStage,
StagesTuple, StatsStage, StdMutationalStage,
},
state::{HasCorpus, StdState, UsesState},
Error, HasMetadata, NopFuzzer,
Expand Down Expand Up @@ -138,7 +138,7 @@ impl<M: Monitor> Instance<'_, M> {

let stats_stage = IfStage::new(
|_, _, _, _| Ok(self.options.tui),
tuple_list!(AflStatsStage::new(Duration::from_secs(5))),
tuple_list!(StatsStage::new(Duration::from_secs(5))),
);

// Feedback to rate the interestingness of an input
Expand Down
22 changes: 13 additions & 9 deletions fuzzers/forkserver/libafl-fuzz/Makefile.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ FUZZER = '${CARGO_TARGET_DIR}/${PROFILE_DIR}/${FUZZER_NAME}'
LLVM_CONFIG = { value = "llvm-config-18", condition = { env_not_set = [
"LLVM_CONFIG",
] } }
AFL_VERSION = "8b35dd49be5f846e945f6d6a9414623d195a99cb"
AFL_VERSION = "78b7e14c73baacf1d88b3c03955e78f5080d17ba"
AFL_DIR = { value = "${PROJECT_DIR}/AFLplusplus" }
AFL_CC_PATH = { value = "${AFL_DIR}/afl-clang-fast" }
CC = { value = "clang" }
Expand All @@ -25,12 +25,16 @@ if [ ! -d "$AFL_DIR" ]; then
cd ${AFL_DIR}
git checkout ${AFL_VERSION}
LLVM_CONFIG=${LLVM_CONFIG} make
fi
'''
[tasks.build_frida_mode]
script_runner = '@shell'
script = '''
cd ${AFL_DIR}
cd frida_mode
LLVM_CONFIG=${LLVM_CONFIG} make
cd ../..
fi
'''

[tasks.build_qemuafl]
script_runner = "@shell"
script = '''
Expand Down Expand Up @@ -77,7 +81,7 @@ script = '''
AFL_PATH=${AFL_DIR} ${AFL_CC_PATH} ./test/test-instr.c -o ./test/out-instr

export LIBAFL_DEBUG_OUTPUT=1
export AFL_CORES=1
export AFL_CORES=0
export AFL_STATS_INTERVAL=1

timeout 5 ${FUZZER} -i ./test/seeds -o ./test/output ./test/out-instr || true
Expand Down Expand Up @@ -109,7 +113,7 @@ script_runner = "@shell"
script = '''
# cmplog TODO: AFL_BENCH_UNTIL_CRASH=1 instead of timeout 15s
AFL_LLVM_CMPLOG=1 AFL_PATH=${AFL_DIR} ${AFL_CC_PATH} ./test/test-cmplog.c -o ./test/out-cmplog
AFL_CORES=1 timeout 5 ${FUZZER} -Z -l 3 -m 0 -V30 -i ./test/seeds_cmplog -o ./test/output-cmplog -c 0 ./test/out-cmplog || true
LIBAFL_DEBUG_OUTPUT=1 AFL_CORES=0 timeout 10 ${FUZZER} -Z -l 3 -m 0 -V30 -i ./test/seeds_cmplog -o ./test/output-cmplog -c 0 ./test/out-cmplog || true
test -n "$( ls ${PROJECT_DIR}/test/output-cmplog/fuzzer_main/hangs/id:0000* ${PROJECT_DIR}/test/output-cmplog/fuzzer_main/crashes/id:0000*)" || {
echo "No crashes found"
exit 1
Expand All @@ -123,7 +127,7 @@ script = '''
${CC} -no-pie ./test/test-instr.c -o ./test/out-frida

export AFL_PATH=${AFL_DIR}
export AFL_CORES=1
export AFL_CORES=0
export AFL_STATS_INTERVAL=1

timeout 5 ${FUZZER} -m 0 -O -i ./test/seeds_frida -o ./test/output-frida -- ./test/out-frida || true
Expand Down Expand Up @@ -162,7 +166,7 @@ test -n "$RUNTIME" -a -n "$RUNTIME_PERSISTENT" && {

unset AFL_FRIDA_PERSISTENT_ADDR
'''
dependencies = ["build_afl", "build_libafl_fuzz"]
dependencies = ["build_afl", "build_frida_mode", "build_libafl_fuzz"]

[tasks.test_qemu]
script_runner = "@shell"
Expand All @@ -171,7 +175,7 @@ ${CC} -pie -fPIE ./test/test-instr.c -o ./test/out-qemu
${CC} -o ./test/out-qemu-cmpcov ./test/test-cmpcov.c

export AFL_PATH=${AFL_DIR}
export AFL_CORES=1
export AFL_CORES=0
export AFL_STATS_INTERVAL=1

timeout 5 ${FUZZER} -m 0 -Q -i ./test/seeds_qemu -o ./test/output-qemu -- ./test/out-qemu || true
Expand Down Expand Up @@ -202,7 +206,7 @@ dependencies = ["build_afl", "build_qemuafl", "build_libafl_fuzz"]
script_runner = "@shell"
script = '''
export AFL_PATH=${AFL_DIR}
export AFL_CORES=1
export AFL_CORES=0
export AFL_STATS_INTERVAL=1

# TODO: test unicorn persistent mode once it's fixed on AFL++
Expand Down
2 changes: 1 addition & 1 deletion fuzzers/forkserver/libafl-fuzz/src/corpus.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ pub fn check_autoresume(fuzzer_dir: &Path, auto_resume: bool) -> Result<Flock<Fi
}
}
if !auto_resume && last_update.saturating_sub(start_time) > OUTPUT_GRACE * 60 {
return Err(Error::illegal_state("The job output directory already exists and contains results! use AFL_AUTORESUME=true or provide \"-\" for -i "));
return Err(Error::illegal_state("The job output directory already exists and contains results! use AFL_AUTORESUME=1 or provide \"-\" for -i "));
}
}
if !auto_resume {
Expand Down
4 changes: 3 additions & 1 deletion fuzzers/forkserver/libafl-fuzz/src/env_parser.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::{collections::HashMap, path::PathBuf, time::Duration};

use libafl::Error;
use libafl::{stages::afl_stats::AFL_FUZZER_STATS_UPDATE_INTERVAL_SECS, Error};
use libafl_bolts::core_affinity::Cores;

use crate::Opt;
Expand Down Expand Up @@ -73,6 +73,8 @@ pub fn parse_envs(opt: &mut Opt) -> Result<(), Error> {
}
if let Ok(res) = std::env::var("AFL_FUZZER_STATS_UPDATE_INTERVAL") {
opt.stats_interval = res.parse()?;
} else {
opt.stats_interval = AFL_FUZZER_STATS_UPDATE_INTERVAL_SECS;
}
if let Ok(res) = std::env::var("AFL_BROKER_PORT") {
opt.broker_port = Some(res.parse()?);
Expand Down
2 changes: 1 addition & 1 deletion fuzzers/forkserver/libafl-fuzz/src/feedback/seed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ where
if !self.ignore_timeouts {
if !self.ignore_seed_issues || self.exit_on_seed_issues {
return Err(Error::invalid_corpus(
"input led to a timeout; use AFL_IGNORE_SEED_ISSUES=true",
"input led to a timeout; use AFL_IGNORE_SEED_ISSUES=1",
));
}
return Ok(false);
Expand Down
69 changes: 50 additions & 19 deletions fuzzers/forkserver/libafl-fuzz/src/fuzzer.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
use std::{
borrow::Cow,
cell::RefCell,
marker::PhantomData,
path::{Path, PathBuf},
rc::Rc,
time::Duration,
};

Expand All @@ -13,18 +15,23 @@ use libafl::{
},
executors::forkserver::{ForkserverExecutor, ForkserverExecutorBuilder},
feedback_and, feedback_or, feedback_or_fast,
feedbacks::{ConstFeedback, CrashFeedback, MaxMapFeedback, TimeFeedback, TimeoutFeedback},
feedbacks::{
CaptureTimeoutFeedback, ConstFeedback, CrashFeedback, MaxMapFeedback, TimeFeedback,
},
fuzzer::StdFuzzer,
inputs::BytesInput,
inputs::{BytesInput, NopTargetBytesConverter},
mutators::{havoc_mutations, tokens_mutations, AFLppRedQueen, StdScheduledMutator, Tokens},
observers::{CanTrack, HitcountsMapObserver, StdMapObserver, TimeObserver},
schedulers::{
powersched::{BaseSchedule, PowerSchedule},
IndexesLenTimeMinimizerScheduler, QueueScheduler, StdWeightedScheduler,
},
stages::{
mutational::MultiMutationalStage, CalibrationStage, ColorizationStage, IfStage,
StagesTuple, StdMutationalStage, StdPowerMutationalStage, SyncFromDiskStage,
afl_stats::{AflStatsStage, CalibrationTime, FuzzTime, SyncTime},
mutational::MultiMutationalStage,
time_tracker::TimeTrackingStageWrapper,
CalibrationStage, ColorizationStage, IfStage, StagesTuple, StdMutationalStage,
StdPowerMutationalStage, SyncFromDiskStage, VerifyTimeoutsStage,
},
state::{
HasCorpus, HasCurrentTestcase, HasExecutions, HasLastReportTime, HasStartTime, StdState,
Expand All @@ -46,7 +53,6 @@ use libafl_targets::{cmps::AFLppCmpLogMap, AFLppCmpLogObserver, AFLppCmplogTraci
use serde::{Deserialize, Serialize};

use crate::{
afl_stats::{AflStatsStage, CalibrationTime, FuzzTime, SyncTime},
corpus::{set_corpus_filepath, set_solution_filepath},
env_parser::AFL_DEFAULT_MAP_SIZE,
executor::find_afl_binary,
Expand All @@ -55,7 +61,7 @@ use crate::{
seed::SeedFeedback,
},
scheduler::SupportedSchedulers,
stages::{mutational_stage::SupportedMutationalStages, time_tracker::TimeTrackingStageWrapper},
stages::mutational_stage::SupportedMutationalStages,
Opt, AFL_DEFAULT_INPUT_LEN_MAX, AFL_DEFAULT_INPUT_LEN_MIN, AFL_HARNESS_FILE_INPUT,
SHMEM_ENV_VAR,
};
Expand Down Expand Up @@ -109,17 +115,21 @@ where
let mut tokens = Tokens::new();
tokens = tokens.add_from_files(&opt.dicts)?;

let user_token_count = tokens.len();

// Create a AFLStatsStage;
let afl_stats_stage = AflStatsStage::new(
opt,
fuzzer_dir.to_path_buf(),
&edges_observer,
user_token_count,
!opt.no_autodict,
core_id,
);
let afl_stats_stage = AflStatsStage::builder()
.stats_file(fuzzer_dir.join("fuzzer_stats"))
.plot_file(fuzzer_dir.join("plot_data"))
.core_id(core_id)
.report_interval(Duration::from_secs(opt.stats_interval))
.map_observer(&edges_observer)
.uses_autotokens(!opt.no_autodict)
.tokens(&tokens)
.banner(opt.executable.display().to_string())
.version("0.13.2".to_string())
.exec_timeout(opt.hang_timeout)
.target_mode(fuzzer_target_mode(opt).to_string())
.build()
.expect("invariant; should never occur");

// Create an observation channel to keep track of the execution time.
let time_observer = TimeObserver::new("time");
Expand All @@ -140,6 +150,20 @@ where
opt,
);

// We need to share this reference as [`VerifyTimeoutsStage`] will toggle this
// value before re-running the alleged timeouts so we don't keep capturing timeouts infinitely.
let enable_capture_timeouts = Rc::new(RefCell::new(false));
let capture_timeout_feedback = CaptureTimeoutFeedback::new(Rc::clone(&enable_capture_timeouts));

// Like AFL++ we re-run all timeouts with double the timeout to assert that they are not false positives
let timeout_verify_stage = IfStage::new(
|_, _, _, _| Ok(!opt.ignore_timeouts),
tuple_list!(VerifyTimeoutsStage::new(
enable_capture_timeouts,
Duration::from_millis(opt.hang_timeout),
)),
);

/*
* Feedback to decide if the Input is "solution worthy".
* We check if it's a crash or a timeout (if we are configured to consider timeouts)
Expand All @@ -153,7 +177,7 @@ where
CrashFeedback::new(),
feedback_and!(
ConstFeedback::new(!opt.ignore_timeouts),
TimeoutFeedback::new()
capture_timeout_feedback,
)
),
MaxMapFeedback::with_name("edges_objective", &edges_observer)
Expand Down Expand Up @@ -396,6 +420,7 @@ where
calibration,
cmplog,
mutational_stage,
timeout_verify_stage,
afl_stats_stage,
sync_stage
);
Expand All @@ -411,7 +436,13 @@ where
)?;
} else {
// The order of the stages matter!
let mut stages = tuple_list!(calibration, mutational_stage, afl_stats_stage, sync_stage);
let mut stages = tuple_list!(
calibration,
mutational_stage,
timeout_verify_stage,
afl_stats_stage,
sync_stage
);

// Run our fuzzer; NO CmpLog
run_fuzzer_with_stages(
Expand All @@ -431,7 +462,7 @@ fn base_executor_builder<'a>(
opt: &'a Opt,
shmem_provider: &'a mut UnixShMemProvider,
fuzzer_dir: &Path,
) -> ForkserverExecutorBuilder<'a, UnixShMemProvider> {
) -> ForkserverExecutorBuilder<'a, NopTargetBytesConverter<BytesInput>, UnixShMemProvider> {
let mut executor = ForkserverExecutor::builder()
.program(opt.executable.clone())
.coverage_map_size(opt.map_size.unwrap_or(AFL_DEFAULT_MAP_SIZE))
Expand Down
3 changes: 1 addition & 2 deletions fuzzers/forkserver/libafl-fuzz/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,6 @@
)]

use std::{collections::HashMap, path::PathBuf, time::Duration};
mod afl_stats;
mod env_parser;
mod feedback;
mod scheduler;
Expand Down Expand Up @@ -188,7 +187,7 @@ struct Opt {
#[arg(short = 'c')]
cmplog: Option<String>,
/// sync to a foreign fuzzer queue directory (requires -M, can be specified up to 32 times)
#[arg(short = 'F', num_args = 32)]
#[arg(short = 'F')]
foreign_sync_dirs: Vec<PathBuf>,
/// fuzzer dictionary (see README.md)
#[arg(short = 'x')]
Expand Down
1 change: 0 additions & 1 deletion fuzzers/forkserver/libafl-fuzz/src/stages/mod.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
pub mod mutational_stage;
pub mod time_tracker;
2 changes: 1 addition & 1 deletion fuzzers/forkserver/libafl-fuzz/test/seeds_cmplog/init
Original file line number Diff line number Diff line change
@@ -1 +1 @@
00000000000000000000000000000000
öööu¼C¼¼‹à
Original file line number Diff line number Diff line change
Expand Up @@ -256,4 +256,8 @@ impl CommandConfigurator<BytesInput> for MyCommandConfigurator {
fn exec_timeout(&self) -> Duration {
Duration::from_secs(5)
}

fn exec_timeout_mut(&mut self) -> &mut Duration {
todo!()
}
}
24 changes: 23 additions & 1 deletion libafl/src/executors/combined.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
//! A `CombinedExecutor` wraps a primary executor and a secondary one
//! In comparison to the [`crate::executors::DiffExecutor`] it does not run the secondary executor in `run_target`.

use core::fmt::Debug;
use core::{fmt::Debug, time::Duration};

use libafl_bolts::tuples::RefIndexable;

use super::HasTimeout;
use crate::{
executors::{Executor, ExitKind, HasObservers},
state::{HasExecutions, UsesState},
Expand Down Expand Up @@ -60,6 +61,27 @@ where
}
}

impl<A, B> HasTimeout for CombinedExecutor<A, B>
where
A: HasTimeout,
B: HasTimeout,
{
#[inline]
fn set_timeout(&mut self, timeout: Duration) {
self.primary.set_timeout(timeout);
self.secondary.set_timeout(timeout);
}

#[inline]
fn timeout(&self) -> Duration {
assert!(
self.primary.timeout() == self.secondary.timeout(),
"Primary and Secondary Executors have different timeouts!"
);
self.primary.timeout()
}
}

impl<A, B> UsesState for CombinedExecutor<A, B>
where
A: UsesState,
Expand Down
Loading
Loading