Repository: microsoft/onefuzz
File: src/agent/onefuzz/src/libfuzzer.rs (Rust)

Code before:
            self.check_input(&empty)
                .await
                .context("checking libFuzzer with empty input")?;
        }

        Ok(())
    }

    pub async fn verify(&self, check_fuzzer_help: bool, inputs: Option<&[&Path]>) -> Result<()> {
        // we’ve seen issues where executables cannot run on the first attempt;
        // for example, executables that depend upon an override in KnownDlls from taking effect
        //
        // so, we let the verification step fail for a while before we commit to its total failure
        let sleep_time = Duration::from_secs(5);
        let max_verification_time = Duration::from_secs(60);
        let started_at = Instant::now();
        let mut attempts = 1;
        loop {
            let result = self
                .verify_inner(check_fuzzer_help, inputs.unwrap_or_default())
                .await;

            match result {
                Ok(()) => return Ok(()),
                Err(e) => {
                    if (Instant::now() + sleep_time) <= (started_at + max_verification_time) {
                        warn!("libfuzzer verification failed, will retry: {e:?}");
                        tokio::time::sleep(sleep_time).await;
                    } else {
                        return Err(e.context(format!(
                            "libfuzzer verification still failing after {attempts} attempts"
                        )));
                    }
                }
            }

            attempts += 1;
        }
    }

    // Verify that the libfuzzer exits with a zero return code with a known
    // good input, which libfuzzer works as we expect.
    async fn check_input(&self, input: &Path) -> Result<()> {
        let mut cmd = self.build_command(
            None,
            None,
            None,
            // Custom args for this run: supply the required input. In this mode,
            // LibFuzzer will only execute one run of fuzzing unless overridden
            Some(&[input.as_ref()]),
            // Filter out any argument starting with `-runs=` from the custom

Review comment (suggestion):
you might want to gate on the number of attempts instead of the running time. The current default running time is [10min](https://github.com/chkeita/onefuzz/blob/256f261f2c1a5fa98fe48a39a14507fa3236b7f6/src/agent/onefuzz/src/libfuzzer.rs#L23)


Code after:
            self.check_input(&empty)
                .await
                .context("checking libFuzzer with empty input")?;
        }

        Ok(())
    }

    pub async fn verify(&self, check_fuzzer_help: bool, inputs: Option<&[&Path]>) -> Result<()> {
        // we’ve seen issues where executables cannot run on the first attempt;
        // for example, executables that depend upon an override in KnownDlls from taking effect
        //
        // so, we let the verification step fail for a while before we commit to its total failure
        const SLEEP_TIME: Duration = Duration::from_secs(5);
        const MAX_ATTEMPTS: usize = 20; // have seen this take 10+ attempts
        let mut attempts = 1;
        loop {
            let result = self
                .verify_inner(check_fuzzer_help, inputs.unwrap_or_default())
                .await;

            match result {
                Ok(()) => return Ok(()),
                Err(e) => {
                    if attempts < MAX_ATTEMPTS {
                        warn!("libfuzzer verification failed, will retry: {e:?}");
                        tokio::time::sleep(SLEEP_TIME).await;
                    } else {
                        return Err(e.context(format!(
                            "libfuzzer verification still failing after {attempts} attempts"
                        )));
                    }
                }
            }

            attempts += 1;
        }
    }

    // Verify that the libfuzzer exits with a zero return code with a known
    // good input, which libfuzzer works as we expect.
    async fn check_input(&self, input: &Path) -> Result<()> {
        let mut cmd = self.build_command(
            None,
            None,
            None,
            // Custom args for this run: supply the required input. In this mode,
            // LibFuzzer will only execute one run of fuzzing unless overridden
            Some(&[input.as_ref()]),
            // Filter out any argument starting with `-runs=` from the custom
            // target options, if supplied, so that it doesn't make more than