From 55d1e6b1b6b1ddb541dddfecd2e3463b8451a466 Mon Sep 17 00:00:00 2001 From: Gary Hu <43922980+Gy-Hu@users.noreply.github.com> Date: Fri, 24 Apr 2026 16:15:50 +0800 Subject: [PATCH] fuzz: avoid panics in append_function on generic functions Closes #21. The fuzzer previously aborted when probing generic functions whose fixed and derived type arguments disagreed (append.rs:113). The sibling `PartialFound` branch already handles the same class of conflict by returning `None`, so match that pattern here. Relax four adjacent fallible sites to the same `debug! + return None` pattern so the fuzzer can skip rather than crash when: - the function identifier is not in the ABI map - `gen_input_arg` fails to synthesise an initial value (two call sites) - a `balance`/`coin` parameter does not substitute to a struct Convert the two pattern-match `else` arms that guard just-constructed `MoveSequenceCall::Call` values to `unreachable!`, which better reflects the invariant. Verified by rerunning the saved flash_lender benchmark (`target/benchmarks/movy-flash-fuzz/args.json`, seed 1, 5s): corpus, objectives, and exec count match the pre-change run. --- .../movy-fuzz/src/mutators/sequence/append.rs | 42 ++++++++++++------- 1 file changed, 28 insertions(+), 14 deletions(-) diff --git a/crates/movy-fuzz/src/mutators/sequence/append.rs b/crates/movy-fuzz/src/mutators/sequence/append.rs index ad4b8a5..8e6f082 100644 --- a/crates/movy-fuzz/src/mutators/sequence/append.rs +++ b/crates/movy-fuzz/src/mutators/sequence/append.rs @@ -83,14 +83,17 @@ where arguments: vec![], }); let MoveSequenceCall::Call(movecall) = &mut cmd else { - panic!("Expected MoveCall command"); + unreachable!("cmd was just constructed as MoveSequenceCall::Call"); }; debug!("Adding function: {:?}", function_ident); - let function = state + let Some(function) = state .fuzz_state() .get_function(&addr, mname, fname) - .unwrap_or_else(|| panic!("Function not found: {}::{}::{}", addr, mname, fname)) - .clone(); + .cloned() + else { + debug!("Function not found: {addr}::{mname}::{fname}, skipping append"); + return None; + }; let mut struct_params = function .parameters .clone() @@ -110,7 +113,10 @@ where let mut fixed_ty_args = fixed_ty_args; for (i, (_, ty_tag)) in fixed_args.iter() { if fixed_ty_args.contains_key(i) && fixed_ty_args[i] != *ty_tag { - panic!("Conflicting type arguments for index {}", i); + debug!( + "Conflicting type arguments for index {i} in {addr}::{mname}::{fname}, skipping" + ); + return None; } fixed_ty_args.insert(*i, ty_tag.clone()); } @@ -140,12 +146,12 @@ where continue; } debug!("Generating initial value for parameter {}: {:?}", i, param); - let init_value = param.gen_input_arg().unwrap_or_else(|| { - panic!( - "Failed to generate initial value for parameter {}: {:?}", - i, param - ) - }); + let Some(init_value) = param.gen_input_arg() else { + debug!( + "Failed to generate initial value for parameter {i}: {param:?}, skipping {addr}::{mname}::{fname}" + ); + return None; + }; let mut init_value = MutableValue::new(init_value); init_value.mutate(state, &BTreeSet::new(), false); let init_value = init_value.value; @@ -287,7 +293,7 @@ where ) { let MoveSequenceCall::Call(new_movecall) = ptb.commands.last_mut().unwrap() else { - panic!("Expected MoveCall command"); + unreachable!("append_function always pushes MoveSequenceCall::Call"); }; let mut ty_args: BTreeMap = ty_args.clone().into_iter().collect::>(); @@ -319,7 +325,12 @@ where continue; } debug!("Generating initial value for parameter {}: {:?}", i, param); - let init_value = param.gen_input_arg().unwrap(); + let Some(init_value) = param.gen_input_arg() else { + debug!( + "Failed to generate initial value for parameter {i}: {param:?}, skipping {addr}::{mname}::{fname}" + ); + return None; + }; let mut init_value = MutableValue::new(init_value); init_value.mutate(state, &BTreeSet::new(), false); let init_value = init_value.value; @@ -426,7 +437,10 @@ where .map(|(j, ty_arg)| (j as u16, ty_arg.clone())) .collect::>(); let MoveTypeTag::Struct(s) = param.subst(&ty_args_map).unwrap() else { - panic!("Expected {special_string} parameter to be a struct"); + debug!( + "Expected {special_string} parameter to be a struct in {addr}::{mname}::{fname}, skipping" + ); + return None; }; let old_arg = std::mem::replace(arg, SequenceArgument::Result(ptb.commands.len() as u16));