Find a testbed corpora for a program. The testbed corpora should be good enough to cover the program's code.
(program_path: &Path, deopt: &Deopt)
| 318 | |
| 319 | /// Find a testbed corpora for a program. The testbed corpora should be good enough to cover the program's code. |
| 320 | pub fn find_testbed_corpora(program_path: &Path, deopt: &Deopt) -> Result<PathBuf> { |
| 321 | log::debug!("Find testbed corpora for program: {:?}", program_path); |
| 322 | static CACHE: OnceCell<RwLock<Vec<PathBuf>>> = OnceCell::new(); |
| 323 | let cache = CACHE.get_or_init(|| RwLock::new(Vec::new())); |
| 324 | |
| 325 | let executor = Executor::new(deopt)?; |
| 326 | let seed_id = Program::load_from_path(program_path)?.id; |
| 327 | executor.compile_seed(seed_id)?; |
| 328 | let fuzzer_code = deopt.get_work_seed_by_id(seed_id)?; |
| 329 | let work_dir = get_file_dirname(&fuzzer_code); |
| 330 | let fuzzer_cov: PathBuf = fuzzer_code.with_extension("cov.out"); |
| 331 | |
| 332 | let mut ranked_files = Vec::new(); |
| 333 | |
| 334 | for cache_file in cache.read().unwrap().iter() { |
| 335 | let cov = get_corpora_coverage(&fuzzer_code, &fuzzer_cov, cache_file, &executor); |
| 336 | if let Err(err) = cov { |
| 337 | log::error!("{err}"); |
| 338 | break; |
| 339 | } |
| 340 | let cov = cov?; |
| 341 | let cov_score = cov.get_total_summary().count_covered_branches(); |
| 342 | ranked_files.push((cache_file.to_path_buf(), cov_score)); |
| 343 | if !sanitize_by_fuzzer_coverage(&fuzzer_code, deopt, &cov)? { |
| 344 | return Ok(cache_file.to_path_buf()); |
| 345 | } |
| 346 | } |
| 347 | |
| 348 | // use the minimized corpus to reduce time cost. |
| 349 | let corpus_dir: PathBuf = [work_dir.clone(), "corpus".into()].iter().collect(); |
| 350 | let corpus_files = crate::deopt::utils::read_all_files_in_dir(&corpus_dir)?; |
| 351 | |
| 352 | let mut max_branch = 0; |
| 353 | let mut max_corpora = None; |
| 354 | for corpora in corpus_files { |
| 355 | let cov = get_corpora_coverage(&fuzzer_code, &fuzzer_cov, &corpora, &executor); |
| 356 | if let Err(err) = cov { |
| 357 | log::error!("{err}"); |
| 358 | break; |
| 359 | } |
| 360 | let cov = cov?; |
| 361 | if sanitize_by_fuzzer_coverage(&fuzzer_code, deopt, &cov)? { |
| 362 | continue; |
| 363 | } |
| 364 | let covered_branch = cov.get_total_summary().count_covered_branches(); |
| 365 | if covered_branch > max_branch { |
| 366 | max_branch = covered_branch; |
| 367 | max_corpora = Some(corpora.clone()); |
| 368 | } |
| 369 | } |
| 370 | if let Some(corpora) = max_corpora { |
| 371 | cache.write().unwrap().push(corpora.clone()); |
| 372 | return Ok(corpora); |
| 373 | } |
| 374 | if !ranked_files.is_empty() { |
| 375 | ranked_files.sort_by_key(|a| a.1); |
| 376 | let corpora = ranked_files |
| 377 | .last() |
no test coverage detected