diff --git a/src/project.rs b/src/project.rs index 01e6006..bf2fbbb 100644 --- a/src/project.rs +++ b/src/project.rs @@ -266,36 +266,27 @@ impl FuzzProject { Ok(cmd) } - fn target_dir(&self, build: &options::BuildOptions) -> Result { - if build.coverage { - Ok(env::current_dir()? - .join("target") - .join(default_target()) - .join("coverage")) + // note: never returns Ok(None) if build.coverage is true + fn target_dir(&self, build: &options::BuildOptions) -> Result> { + // Use the user-provided target directory, if provided. Otherwise if building for coverage, + // use the coverage directory + if let Some(target_dir) = build.target_dir.as_ref() { + return Ok(Some(PathBuf::from(target_dir))); + } else if build.coverage { + // To ensure that fuzzing and coverage-output generation can run in parallel, we + // produce a separate binary for the coverage command. + let current_dir = env::current_dir()?; + Ok(Some( + current_dir + .join("target") + .join(default_target()) + .join("coverage"), + )) } else { - Ok(build - .target_dir - .as_ref() - .map(PathBuf::from) - .unwrap_or_else(|| self.project_dir.join("target"))) + Ok(None) } } - fn cargo_build_bin_path( - &self, - build: &options::BuildOptions, - fuzz_target: &str, - ) -> Result { - let profile_subdir = if build.dev { "debug" } else { "release" }; - - let bin_path = self - .target_dir(&build)? - .join(&build.triple) - .join(profile_subdir) - .join(fuzz_target); - Ok(bin_path) - } - pub fn exec_build( &self, mode: options::BuildMode, @@ -314,8 +305,7 @@ impl FuzzProject { cmd.arg("--bins"); } - if build.target_dir.is_some() || build.coverage { - let target_dir = self.target_dir(&build)?; + if let Some(target_dir) = self.target_dir(&build)? { cmd.arg("--target-dir").arg(target_dir); } @@ -710,7 +700,23 @@ impl FuzzProject { coverage_dir: &Path, input_file: &Path, ) -> Result<(Command, String)> { - let mut cmd = Command::new(self.cargo_build_bin_path(&coverage.build, &coverage.target)?); + let bin_path = { + let profile_subdir = if coverage.build.dev { + "debug" + } else { + "release" + }; + + let target_dir = self + .target_dir(&coverage.build)? + .expect("target dir for coverage command should never be None"); + target_dir + .join(&coverage.build.triple) + .join(profile_subdir) + .join(&coverage.target) + }; + + let mut cmd = Command::new(bin_path); // Raw coverage data will be saved in `coverage/` directory. let input_file_name = input_file