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
11 changes: 10 additions & 1 deletion crates/movy-analysis/src/type_graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ use std::{
};

use movy_types::abi::{
MoveAbiSignatureToken, MoveFunctionAbi, MoveModuleAbi, MoveModuleId, MovePackageAbi,
MoveAbiSignatureToken, MoveFunctionAbi, MoveFunctionVisibility, MoveModuleAbi, MoveModuleId,
MovePackageAbi,
};
use petgraph::{graph::NodeIndex, visit::EdgeRef};
use serde::{Deserialize, Serialize};
Expand Down Expand Up @@ -126,6 +127,7 @@ impl MoveTypeGraph {
pub fn find_consumers(
&self,
ty: &MoveAbiSignatureToken,
public_only: bool,
) -> Vec<(&MoveModuleId, &MoveFunctionAbi)> {
let mut consumers = vec![];
for (graph_ty, node) in self.tys.iter() {
Expand All @@ -137,6 +139,9 @@ impl MoveTypeGraph {
.edges_directed(*node, petgraph::Direction::Outgoing)
{
if let TypeGraphNode::Function(m, f) = &self.graph[edge.target()] {
if public_only && f.visibility != MoveFunctionVisibility::Public {
continue;
}
consumers.push((m, f));
}
}
Expand All @@ -148,6 +153,7 @@ impl MoveTypeGraph {
pub fn find_producers(
&self,
ty: &MoveAbiSignatureToken,
public_only: bool,
) -> Vec<(MoveModuleId, MoveFunctionAbi)> {
let mut producers = vec![];
for (graph_ty, node) in self.tys.iter() {
Expand All @@ -159,6 +165,9 @@ impl MoveTypeGraph {
.edges_directed(*node, petgraph::Direction::Incoming)
{
if let TypeGraphNode::Function(m, f) = &self.graph[edge.source()] {
if public_only && f.visibility != MoveFunctionVisibility::Public {
continue;
}
producers.push((m.clone(), f.clone()));
}
}
Expand Down
12 changes: 11 additions & 1 deletion crates/movy-fuzz/src/executor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,8 +148,18 @@ where
.expect("tracer should be present when tracing is enabled")
.outcome();

trace!("Execution finished with status: {:?}", effects.status());

let (stage_idx, success) = match effects.status() {
ExecutionStatus::Failure { command, .. } => (command.map(|c| c), false),
ExecutionStatus::Failure { command, .. } => (
// command index may be out of bound when meeting non-aborted error
if command.is_some_and(|c| c < input.sequence().commands.len()) {
command.clone()
} else {
None
},
false,
),
_ => (None, true),
};
if effects.status().is_err() {
Expand Down
2 changes: 1 addition & 1 deletion crates/movy-fuzz/src/meta.rs
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ fn should_skip_function(base: &Metadata, func_data: &MoveFunctionAbi) -> bool {
MoveAbiSignatureToken::Reference(_) | MoveAbiSignatureToken::MutableReference(_)
);
let hanging_hot_potato =
ret_ty.is_hot_potato() && base.type_graph.find_consumers(ret_ty).is_empty();
ret_ty.is_hot_potato() && base.type_graph.find_consumers(ret_ty, true).is_empty();
if self_used || ret_ref || hanging_hot_potato {
return true;
}
Expand Down
21 changes: 12 additions & 9 deletions crates/movy-fuzz/src/mutators/object_data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,7 @@ impl ObjectData {
// continue; // Skip parameters that have the Copy ability
// }
let instantiated_param = param.subst(ty_args_map).unwrap();
let partial_instantiation = param.partial_subst(ty_args_map);
existing_objects
.get_mut(&instantiated_param)
.unwrap_or_else(|| {
Expand All @@ -203,25 +204,26 @@ impl ObjectData {
if matches!(arg, SequenceArgument::Input(_)) {
continue; // Skip input arguments for key store and hot potatoes
}
if param.is_balance() {
if partial_instantiation.is_balance() {
balances.retain(|a| *a != *arg); // Remove from balances if it is a balance object
}
if param.is_key_store() {
if partial_instantiation.is_key_store() {
key_store_objects.retain(|a| *a != *arg); // Remove from key_store_objects if it is a key store object
}
if param.is_hot_potato() {
if partial_instantiation.is_hot_potato() {
hot_potatoes.remove(
hot_potatoes
.iter()
.position(|x| x == &instantiated_param)
.unwrap_or_else(|| {
panic!(
"Expected hot potato object for type {:?}, input {}",
"Expected hot potato object for type {}, input {}, hot potatoes {:?}",
instantiated_param,
MoveFuzzInput {
sequence: ptb.clone(),
..Default::default()
}
},
hot_potatoes
)
}),
);
Expand Down Expand Up @@ -265,6 +267,7 @@ impl ObjectData {
continue;
}
let instantiated_ret_ty = ret_ty.subst(ty_args_map).unwrap();
let partial_instantiation = ret_ty.partial_subst(ty_args_map);
if !matches!(instantiated_ret_ty, MoveTypeTag::Struct(_)) {
continue; // Only process struct return types
}
Expand All @@ -277,13 +280,13 @@ impl ObjectData {
.entry(instantiated_ret_ty.clone())
.or_default()
.push((res_arg, Gate::Owned));
if ret_ty.is_balance() {
if partial_instantiation.is_balance() {
balances.push(res_arg);
}
if ret_ty.is_key_store() {
if partial_instantiation.is_key_store() {
key_store_objects.push(res_arg);
}
if ret_ty.is_hot_potato() {
if partial_instantiation.is_hot_potato() {
hot_potatoes.push(instantiated_ret_ty);
}
}
Expand Down Expand Up @@ -899,7 +902,7 @@ where
.flat_map(|type_tag| {
meta_state
.type_graph
.find_consumers(&MoveAbiSignatureToken::from_type_tag_lossy(type_tag))
.find_consumers(&MoveAbiSignatureToken::from_type_tag_lossy(type_tag), true)
.iter()
.map(|(module_id, consumer_function)| {
FunctionIdent::new(
Expand Down
5 changes: 4 additions & 1 deletion crates/movy-fuzz/src/mutators/sequence/append.rs
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,10 @@ where
}
let arg_type = struct_params.remove(0).partial_subst(&ty_args);

let funcs = state.fuzz_state().type_graph.find_producers(&arg_type);
let funcs = state
.fuzz_state()
.type_graph
.find_producers(&arg_type, true);
// except itself
let funcs = funcs
.iter()
Expand Down
6 changes: 5 additions & 1 deletion crates/movy-fuzz/src/mutators/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,10 @@ impl StageReplay {
self.reset_progress();
return StageReplayAction::Fresh;
};
debug!(
"StageReplay decide: current stage idx {}, recorded stage idx {:?}, attempts {}",
stage_idx, self.stage_idx, self.attempts
);

let prev_stage = self.stage_idx;
self.stage_idx = match self.stage_idx {
Expand Down Expand Up @@ -266,7 +270,7 @@ where
let mut ty_args = if let Some(stage_idx) = stage_idx {
let Some(cmd) = ptb.commands.get_mut(*stage_idx) else {
warn!(
"Stage idx {} out of bounds for commands: {:?}",
"Stage idx {} out of bounds for commands mutating ty args: {:?}",
stage_idx, ptb.commands
);
return MutationResult::Skipped;
Expand Down
14 changes: 12 additions & 2 deletions crates/movy-replay/src/tracer/concolic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,7 @@ impl ConcolicState {
self.stack.pop();
}
if self.stack.len() != s.value.len() {
debug!(
warn!(
"stack: {:?}, stack from trace: {:?}, event: {:?}, disabling concolic execution",
self.stack, s.value, event
);
Expand Down Expand Up @@ -423,6 +423,13 @@ impl ConcolicState {
instruction,
extra,
} => {
trace!(
"Before instruction at pc {}: {:?}, extra: {:?}. Current stack: {:?}",
pc,
instruction,
extra,
stack.map(|s| &s.value)
);
match instruction {
Bytecode::Pop
| Bytecode::BrTrue(_)
Expand Down Expand Up @@ -1003,11 +1010,14 @@ impl ConcolicState {
_ => unreachable!(),
}
}
Bytecode::VariantSwitch(_) => {
self.stack.pop();
}
_ => {}
}
}
_ => {
trace!("Unsupported event: {:?}", event);
// trace!("Unsupported event: {:?}", event);
}
}
None
Expand Down