fuchsia_fuzzctl/
artifact.rs1use crate::input::Input;
6use crate::util::digest_path;
7use anyhow::{bail, Context as _, Result};
8use fidl_fuchsia_fuzzer::{Artifact as FidlArtifact, Result_ as FuzzResult};
9use std::fs;
10use std::path::{Path, PathBuf};
11use zx_status as zx;
12
13pub struct Artifact {
15 pub result: FuzzResult,
17
18 pub path: Option<PathBuf>,
20}
21
22impl Artifact {
23 pub fn ok() -> Self {
25 Self { result: FuzzResult::NoErrors, path: None }
26 }
27
28 pub fn from_result(result: FuzzResult) -> Self {
30 Self { result, path: None }
31 }
32
33 pub fn pathname(&self) -> String {
35 self.path.as_ref().map(|p| p.to_string_lossy().to_string()).unwrap_or(String::default())
36 }
37}
38
39pub async fn save_artifact<P: AsRef<Path>>(
48 fidl_artifact: FidlArtifact,
49 out_dir: P,
50) -> Result<Option<Artifact>> {
51 if let Some(e) = fidl_artifact.error {
52 if e == zx::Status::PEER_CLOSED.into_raw() {
53 return Ok(None);
54 }
55 bail!("workflow returned an error: ZX_ERR_{}", e);
56 }
57 let result = fidl_artifact.result.context("invalid FIDL artifact: missing result")?;
58 let mut artifact = Artifact::from_result(result);
59 if let Some(fidl_input) = fidl_artifact.input {
60 let input =
61 Input::try_receive(fidl_input).await.context("failed to receive fuzzer input data")?;
62 if artifact.result != FuzzResult::NoErrors {
63 let path = digest_path(out_dir, Some(artifact.result), &input.data);
64 fs::write(&path, input.data).with_context(|| {
65 format!("failed to write fuzzer input to '{}'", path.to_string_lossy())
66 })?;
67 artifact.path = Some(path);
68 }
69 };
70 Ok(Some(artifact))
71}
72
73#[cfg(test)]
74mod tests {
75 use super::save_artifact;
76 use crate::input::InputPair;
77 use crate::util::digest_path;
78 use anyhow::Result;
79 use fidl_fuchsia_fuzzer::{Artifact as FidlArtifact, Result_ as FuzzResult};
80 use fuchsia_fuzzctl_test::{verify_saved, Test};
81 use futures::join;
82
83 #[fuchsia::test]
84 async fn test_save_artifact() -> Result<()> {
85 let test = Test::try_new()?;
86 let saved_dir = test.create_dir("saved")?;
87
88 let input_pair = InputPair::try_from_data(b"data".to_vec())?;
89 let (fidl_input, input) = input_pair.as_tuple();
90 let send_fut = input.send();
91 let fidl_artifact = FidlArtifact {
92 result: Some(FuzzResult::Crash),
93 input: Some(fidl_input),
94 ..Default::default()
95 };
96 let save_fut = save_artifact(fidl_artifact, &saved_dir);
97 let results = join!(send_fut, save_fut);
98 assert!(results.0.is_ok());
99 assert!(results.1.is_ok());
100 let saved = digest_path(&saved_dir, Some(FuzzResult::Crash), b"data");
101 verify_saved(&saved, b"data")?;
102 Ok(())
103 }
104}