Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
30 changes: 22 additions & 8 deletions crates/movy-fuzz/src/executor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,26 @@ where
.expect("no code ob installed");
code_ob.reset_map()?;
}
let extra = ExecutionExtraOutcome {
logs: trace_outcome.logs,
solver: trace_outcome.concolic,
stage_idx,
success,
};
let events: Vec<_> = events.into_iter().map(|e| e.into()).collect();

// Expose preliminary outcome so oracles can inspect events.
let mut exec = ExecutionOutcome {
events_verdict: trace_outcome.verdict,
events: events.clone(),
allowed_success: success,
findings: trace_outcome.findings.clone(),
};
state.extra_state_mut().global_outcome = Some(GlobalOutcome {
exec: exec.clone(),
extra: extra.clone(),
});

let oracle_vulns = self.oracles.done_execution(&db, state, &effects)?;
if !oracle_vulns.is_empty() {
trace_outcome.findings.extend(oracle_vulns.iter().cloned());
Expand All @@ -171,15 +191,9 @@ where
} else {
trace_outcome.verdict
};
let extra = ExecutionExtraOutcome {
logs: trace_outcome.logs,
solver: trace_outcome.concolic,
stage_idx,
success,
};
let exec = ExecutionOutcome {
exec = ExecutionOutcome {
events_verdict: kind,
events: events.into_iter().map(|e| e.into()).collect(),
events,
allowed_success: success,
findings: trace_outcome.findings.clone(),
};
Expand Down
42 changes: 24 additions & 18 deletions crates/movy-fuzz/src/meta.rs
Original file line number Diff line number Diff line change
Expand Up @@ -310,29 +310,35 @@ fn apply_function_filters(
let pkg = func.0.module_address;
let module_id = &func.0;
if let Some(set) = &include_pkgs
&& !set.contains(&pkg) {
return false;
}
&& !set.contains(&pkg)
{
return false;
}
if let Some(set) = &exclude_pkgs
&& set.contains(&pkg) {
return false;
}
&& set.contains(&pkg)
{
return false;
}
if let Some(set) = &include_funcs
&& !set.contains(func) {
return false;
}
&& !set.contains(func)
{
return false;
}
if let Some(set) = &exclude_funcs
&& set.contains(func) {
return false;
}
&& set.contains(func)
{
return false;
}
if let Some(set) = &include_modules
&& !set.contains(module_id) {
return false;
}
&& !set.contains(module_id)
{
return false;
}
if let Some(set) = &exclude_modules
&& set.contains(module_id) {
return false;
}
&& set.contains(module_id)
{
return false;
}
true
})
.collect()
Expand Down
224 changes: 121 additions & 103 deletions crates/movy-fuzz/src/mutators/sequence/hooks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,66 +104,83 @@ fn append_hook_call<S>(

let mut fixed_args: BTreeMap<u16, (SequenceArgument, MoveTypeTag)> = BTreeMap::new();
let mut fixed_ty_args: BTreeMap<u16, MoveTypeTag> = BTreeMap::new();
if let Some(ctx) = ctx_arg
&& let Some(param_ty) = hook_abi
.parameters.first()
let param_offset = if ctx_arg.is_some() { 1 } else { 0 };
if let Some(ctx) = ctx_arg {
if let Some(param_ty) = hook_abi
.parameters
.get(0)
.and_then(|p| p.subst(&BTreeMap::new()))
{
fixed_args.insert(0, (ctx, param_ty));
}
if let Some((target_call, target_abi, maybe_idx)) = target {
}
if let Some((target_call, target_abi, _maybe_idx)) = target {
// Hook must mirror the target function signature (plus optional context).
if hook_abi.type_parameters.len() != target_call.type_arguments.len() {
warn!(
"skip hook {:?} due to mismatched type parameters: hook {} vs target {}",
hook_ident,
hook_abi.type_parameters.len(),
target_call.type_arguments.len()
);
return;
}
for (i, ty) in target_call.type_arguments.iter().enumerate() {
fixed_ty_args.insert(i as u16, ty.clone());
}

if hook_abi.parameters.len() != param_offset + target_abi.parameters.len() {
warn!(
"skip hook {:?} due to mismatched params: hook {} vs target {} (+ctx {})",
hook_ident,
hook_abi.parameters.len(),
target_abi.parameters.len(),
param_offset
);
return;
}

let ty_args_map = target_call
.type_arguments
.iter()
.enumerate()
.map(|(i, ty)| (i as u16, ty.clone()))
.collect::<BTreeMap<_, _>>();
for (i, ty) in target_call.type_arguments.iter().enumerate() {
if i < hook_abi.type_parameters.len() {
fixed_ty_args.insert(i as u16, ty.clone());
}
}
let mut candidates: Vec<(MoveTypeTag, SequenceArgument)> = target_call
.arguments
let hook_ty_args_map = fixed_ty_args.clone();
for (i, (hook_param, target_param)) in hook_abi
.parameters
.iter()
.skip(param_offset)
.zip(target_abi.parameters.iter())
.filter_map(|(arg, param)| param.subst(&ty_args_map).map(|ty| (ty, *arg)))
.collect();
if let Some(target_idx) = maybe_idx {
let ret_args = if target_abi.return_paramters.len() == 1 {
vec![SequenceArgument::Result(target_idx)]
} else {
target_abi
.return_paramters
.iter()
.enumerate()
.map(|(i, _)| SequenceArgument::NestedResult(target_idx, i as u16))
.collect::<Vec<_>>()
.enumerate()
{
let Some(hook_ty) = hook_param.subst(&hook_ty_args_map) else {
warn!(
"skip hook {:?} due to unsubstitutable hook param {}",
hook_ident, i
);
return;
};
candidates.extend(
ret_args
.into_iter()
.zip(target_abi.return_paramters.iter())
.filter_map(|(arg, ret_ty)| ret_ty.subst(&ty_args_map).map(|ty| (ty, arg))),
);
}
let mut used = vec![false; candidates.len()];
let hook_ty_args_map = fixed_ty_args.clone();
for (idx, param) in hook_abi.parameters.iter().enumerate() {
if ctx_arg.is_some() && idx == 0 {
continue;
}
let Some(param_ty) = param.subst(&hook_ty_args_map) else {
continue;
let Some(target_ty) = target_param.subst(&ty_args_map) else {
warn!(
"skip hook {:?} due to unsubstitutable target param {}",
hook_ident, i
);
return;
};
if let Some((cand_idx, (_, arg))) = candidates
.iter()
.enumerate()
.find(|(i, (ty, _))| !used[*i] && *ty == param_ty)
{
fixed_args.insert(idx as u16, (*arg, param_ty.clone()));
used[cand_idx] = true;
if hook_ty != target_ty {
warn!(
"skip hook {:?} due to param type mismatch at {}: hook {:?} vs target {:?}",
hook_ident, i, hook_ty, target_ty
);
return;
}
let arg = target_call
.arguments
.get(i)
.cloned()
.unwrap_or_else(|| SequenceArgument::Input(0));
fixed_args.insert((param_offset + i) as u16, (arg, hook_ty));
}
}

Expand Down Expand Up @@ -262,67 +279,68 @@ where
)
.cloned();
if let Some(target_abi) = target_abi
&& let Some(hooks) = function_hooks.get(&func_ident) {
let mut hook_ctx: Option<SequenceArgument> = None;
if let Some((create_ctx, _)) = context_idents.as_ref() {
if let Some((_, rets)) = append_function(
state,
&mut ptb,
create_ctx,
BTreeMap::new(),
BTreeMap::new(),
&vec![],
true,
0,
) {
hook_ctx = rets.first().cloned();
} else {
warn!(
"Failed to append context creation function {:?}",
create_ctx
);
}
}
for hook in hooks.pre_hooks.iter() {
append_hook_call(
state,
&mut ptb,
hook,
Some((&remapped_call, &target_abi, None)),
hook_ctx,
);
}
let main_idx = ptb.commands.len() as u16;
ptb.commands
.push(MoveSequenceCall::Call(remapped_call.clone()));
index_map.push(main_idx);
for hook in hooks.post_hooks.iter() {
append_hook_call(
state,
&mut ptb,
hook,
Some((&remapped_call, &target_abi, Some(main_idx))),
hook_ctx,
);
}
if let (Some(ctx_arg), Some((_, destroy_ctx)), Some(param_ty)) =
(hook_ctx, context_idents.as_ref(), destroy_param_ty.clone())
{
let mut fixed_args = BTreeMap::new();
fixed_args.insert(0u16, (ctx_arg, param_ty));
let _ = append_function(
state,
&mut ptb,
destroy_ctx,
fixed_args,
BTreeMap::new(),
&vec![],
true,
0,
&& let Some(hooks) = function_hooks.get(&func_ident)
{
let mut hook_ctx: Option<SequenceArgument> = None;
if let Some((create_ctx, _)) = context_idents.as_ref() {
if let Some((_, rets)) = append_function(
state,
&mut ptb,
create_ctx,
BTreeMap::new(),
BTreeMap::new(),
&vec![],
true,
0,
) {
hook_ctx = rets.first().cloned();
} else {
warn!(
"Failed to append context creation function {:?}",
create_ctx
);
}
continue;
}
for hook in hooks.pre_hooks.iter() {
append_hook_call(
state,
&mut ptb,
hook,
Some((&remapped_call, &target_abi, None)),
hook_ctx,
);
}
let main_idx = ptb.commands.len() as u16;
ptb.commands
.push(MoveSequenceCall::Call(remapped_call.clone()));
index_map.push(main_idx);
for hook in hooks.post_hooks.iter() {
append_hook_call(
state,
&mut ptb,
hook,
Some((&remapped_call, &target_abi, Some(main_idx))),
hook_ctx,
);
}
if let (Some(ctx_arg), Some((_, destroy_ctx)), Some(param_ty)) =
(hook_ctx, context_idents.as_ref(), destroy_param_ty.clone())
{
let mut fixed_args = BTreeMap::new();
fixed_args.insert(0u16, (ctx_arg, param_ty));
let _ = append_function(
state,
&mut ptb,
destroy_ctx,
fixed_args,
BTreeMap::new(),
&vec![],
true,
0,
);
}
continue;
}
let new_idx = ptb.commands.len() as u16;
ptb.commands.push(MoveSequenceCall::Call(remapped_call));
index_map.push(new_idx);
Expand Down
1 change: 1 addition & 0 deletions crates/movy-fuzz/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -382,6 +382,7 @@ where
let input = _testcase.input_mut().as_mut().unwrap();
let execution_outcome = outcome.exec;
*input.outcome_mut() = Some(execution_outcome);
*input.display_mut() = Some(input.format());
}

#[cfg(feature = "input_display")]
Expand Down
Loading