async fn run_fuzzer(
        &self,
        local_inputs: impl AsRef<std::path::Path>,
        worker_id: usize,
        stats_sender: Option<&StatsSender>,
    ) -> Result<()> {
        let crash_dir = self.create_local_temp_dir().await?;
        let run_id = Uuid::new_v4();

        debug!("starting fuzzer run, run_id = {}", run_id);

        let mut inputs = vec![&self.config.inputs.local_path];
        if let Some(readonly_inputs) = &self.config.readonly_inputs {
            readonly_inputs
                .iter()
                .for_each(|d| inputs.push(&d.local_path));
        }

        let fuzzer = LibFuzzer::new(
            &self.config.target_exe,
            &self.config.target_options,
            &self.config.target_env,
            &self.config.common.setup_dir,
        );
        let mut running = fuzzer.fuzz(crash_dir.path(), local_inputs, &inputs).await?;
        let running_id = running.id();
        let notify = Arc::new(Notify::new());
        let sys_info = task::spawn(report_fuzzer_sys_info(
            worker_id,
            run_id,
            running_id.unwrap_or_default(),
            notify.clone(),
        ));

        // Splitting borrow.
        let stderr = running
            .stderr
            .as_mut()
            .ok_or_else(|| format_err!("stderr not captured"))?;
        let mut stderr = BufReader::new(stderr);

        let mut libfuzzer_output: ArrayDeque<[_; LOGS_BUFFER_SIZE], Wrapping> = ArrayDeque::new();
        loop {
            let mut buf = vec![];
            let bytes_read = stderr.read_until(b'\n', &mut buf).await?;
            if bytes_read == 0 && buf.is_empty() {
                break;
            }
            let line = String::from_utf8_lossy(&buf).to_string();
            if let Some(stats_sender) = stats_sender {
                if let Err(err) = try_report_iter_update(stats_sender, worker_id, run_id, &line) {
                    error!("could not parse fuzzing interation update: {}", err);
                }
            }
            libfuzzer_output.push_back(line);
        }

        let exit_status = running.wait().await;
        notify.notify_one();
        let _ = sys_info.await;

        let exit_status: ExitStatus = exit_status?.into();

        let files = list_files(crash_dir.path()).await?;

        // If the target exits, crashes are required unless
        // 1. Exited cleanly (happens with -runs=N)
        // 2. expect_crash_on_failure is disabled
        if files.is_empty() && !exit_status.success {
            if self.config.expect_crash_on_failure {
                bail!(
                    "libfuzzer exited without generating crashes.  status:{} stderr:{:?}",
                    serde_json::to_string(&exit_status)?,
                    libfuzzer_output
                        .into_iter()
                        .collect::<Vec<String>>()
                        .join("\n")
                );
            } else {
                warn!(
                    "libfuzzer exited without generating crashes, continuing.  status:{} stderr:{:?}",
                    serde_json::to_string(&exit_status)?,
                    libfuzzer_output.into_iter().collect::<Vec<String>>().join("\n")
                );
            }
        }

        for file in &files {
            if let Some(filename) = file.file_name() {
                let dest = self.config.crashes.local_path.join(filename);
                if let Err(e) = tokio::fs::rename(file.clone(), dest.clone()).await {
                    if !dest.exists() {
                        bail!(e)
                    }
                }
            }
        }

        Ok(())
    }
// Fuzz with a libFuzzer until it exits.
//
// While it runs, parse stderr for progress metrics, and report them.
Fuzz with a libFuzzer until it exits.
While it runs, parse stderr for progress metrics, and report them.
Fuzz with a libFuzzer until it exits . While it runs parse stderr for progress metrics and report them .
async fn run_fuzzer(
        &self,
        local_inputs: impl AsRef<std::path::Path>,
        worker_id: usize,
        stats_sender: Option<&StatsSender>,
    ) -> Result<()> {
        let crash_dir = self.create_local_temp_dir().await?;
        let run_id = Uuid::new_v4();
        debug!("starting fuzzer run, run_id = {}", run_id);
        let mut inputs = vec![&self.config.inputs.local_path];
        if let Some(readonly_inputs) = &self.config.readonly_inputs {
            readonly_inputs
                .iter()
                .for_each(|d| inputs.push(&d.local_path));
        }
        let fuzzer = LibFuzzer::new(
            &self.config.target_exe,
            &self.config.target_options,
            &self.config.target_env,
            &self.config.common.setup_dir,
        );
        let mut running = fuzzer.fuzz(crash_dir.path(), local_inputs, &inputs).await?;
        let running_id = running.id();
        let notify = Arc::new(Notify::new());
        let sys_info = task::spawn(report_fuzzer_sys_info(
            worker_id,
            run_id,
            running_id.unwrap_or_default(),
            notify.clone(),
        ));
        // Splitting borrow.
        let stderr = running
            .stderr
            .as_mut()
            .ok_or_else(|| format_err!("stderr not captured"))?;
        let mut stderr = BufReader::new(stderr);
        let mut libfuzzer_output: ArrayDeque<[_; LOGS_BUFFER_SIZE], Wrapping> = ArrayDeque::new();
        loop {
            let mut buf = vec![];
            let bytes_read = stderr.read_until(b'\n', &mut buf).await?;
            if bytes_read == 0 && buf.is_empty() {
                break;
            }
            let line = String::from_utf8_lossy(&buf).to_string();
            if let Some(stats_sender) = stats_sender {
                if let Err(err) = try_report_iter_update(stats_sender, worker_id, run_id, &line) {
                    error!("could not parse fuzzing interation update: {}", err);
                }
            }
            libfuzzer_output.push_back(line);
        }
        let exit_status = running.wait().await;
        notify.notify_one();
        let _ = sys_info.await;
        let exit_status: ExitStatus = exit_status?.into();
        let files = list_files(crash_dir.path()).await?;
        // If the target exits, crashes are required unless
        // 1. Exited cleanly (happens with -runs=N)
        // 2. expect_crash_on_failure is disabled
        if files.is_empty() && !exit_status.success {
            if self.config.expect_crash_on_failure {
                bail!(
                    "libfuzzer exited without generating crashes.  status:{} stderr:{:?}",
                    serde_json::to_string(&exit_status)?,
                    libfuzzer_output
                        .into_iter()
                        .collect::<Vec<String>>()
                        .join("\n")
                );
            } else {
                warn!(
                    "libfuzzer exited without generating crashes, continuing.  status:{} stderr:{:?}",
                    serde_json::to_string(&exit_status)?,
                    libfuzzer_output.into_iter().collect::<Vec<String>>().join("\n")
                );
            }
        }
        for file in &files {
            if let Some(filename) = file.file_name() {
                let dest = self.config.crashes.local_path.join(filename);
                if let Err(e) = tokio::fs::rename(file.clone(), dest.clone()).await {
                    if !dest.exists() {
                        bail!(e)
                    }
                }
            }
        }
        Ok(())
    }
async fn run_fuzzer ( & self , local_inputs : impl AsRef < std :: path :: Path > , worker_id : usize , stats_sender : Option < & StatsSender > , ) -> Result < ( ) > { let crash_dir = self . create_local_temp_dir ( ) . await ? ; let run_id = Uuid :: new_v4 ( ) ; debug ! ( " " run_id ) ; let mut inputs = vec ! [ self config inputs local_path ] ; if let Some ( readonly_inputs ) = & self . config . readonly_inputs { readonly_inputs . iter ( ) . for_each ( | d | inputs . push ( & d . local_path ) ) ; } let fuzzer = LibFuzzer :: new ( & self . config . target_exe , & self . config . target_options , & self . config . target_env , & self . config . common . setup_dir , ) ; let mut running = fuzzer . fuzz ( crash_dir . path ( ) , local_inputs , & inputs ) . await ? ; let running_id = running . id ( ) ; let notify = Arc :: new ( Notify :: new ( ) ) ; let sys_info = task :: spawn ( report_fuzzer_sys_info ( worker_id , run_id , running_id . unwrap_or_default ( ) , notify . clone ( ) , ) ) ; // Splitting borrow. let stderr = running . stderr . as_mut ( ) . ok_or_else ( | | format_err ! ( " " ) ) ? ; let mut stderr = BufReader :: new ( stderr ) ; let mut libfuzzer_output : ArrayDeque < [ _ ; LOGS_BUFFER_SIZE ] , Wrapping > = ArrayDeque :: new ( ) ; loop { let mut buf = vec ! [ ] ; let bytes_read = stderr . read_until ( b'\n' , & mut buf ) . await ? ; if bytes_read == 0 && buf . is_empty ( ) { break ; } let line = String :: from_utf8_lossy ( & buf ) . to_string ( ) ; if let Some ( stats_sender ) = stats_sender { if let Err ( err ) = try_report_iter_update ( stats_sender , worker_id , run_id , & line ) { error ! ( " " err ) ; } } libfuzzer_output . push_back ( line ) ; } let exit_status = running . wait ( ) . await ; notify . notify_one ( ) ; let _ = sys_info . await ; let exit_status : ExitStatus = exit_status ? . into ( ) ; let files = list_files ( crash_dir . path ( ) ) . await ? ; // If the target exits, crashes are required unless // 1. Exited cleanly (happens with -runs=N) // 2. expect_crash_on_failure is disabled if files . is_empty ( ) && ! exit_status . success { if self . config . expect_crash_on_failure { bail ! ( " " serde_json to_string ( exit_status ) libfuzzer_output into_iter ( ) collect Vec String ( ) join ( " \n " ) ) ; } else { warn ! ( " " serde_json to_string ( exit_status ) libfuzzer_output into_iter ( ) collect Vec String ( ) join ( " \n " ) ) ; } } for file in & files { if let Some ( filename ) = file . file_name ( ) { let dest = self . config . crashes . local_path . join ( filename ) ; if let Err ( e ) = tokio :: fs :: rename ( file . clone ( ) , dest . clone ( ) ) . await { if ! dest . exists ( ) { bail ! ( e ) } } } } Ok ( ( ) ) }
Fuzz with a libFuzzer until it exits.
Fuzz with a libFuzzer until it exits .
&self
local_inputs
impl AsRef<std::path::Path>
worker_id
usize
stats_sender
Option<&StatsSender>
&self
local_inputs
impl AsRef<std::path::Path>
worker_id
usize
stats_sender
Option<&StatsSender>