(&mut self, workdir: &std::path::Path)
| 148 | |
| 149 | impl CorpusStore<MultiStream> { |
| 150 | pub fn maybe_save(&mut self, workdir: &std::path::Path) -> anyhow::Result<()> { |
| 151 | if self.last_save_cases == self.test_cases.len() |
| 152 | && self.replaced.is_empty() |
| 153 | && self.last_save_time.elapsed().as_secs() < 60 |
| 154 | { |
| 155 | return Ok(()); |
| 156 | } |
| 157 | |
| 158 | if self.last_save_time.elapsed().as_secs() <= 2 { |
| 159 | return Ok(()); |
| 160 | } |
| 161 | |
| 162 | // Save any new testcases |
| 163 | for test_case in self.test_cases[self.last_save_cases..] |
| 164 | .iter() |
| 165 | .chain(self.replaced.drain(..).map(|id| &self.test_cases[id])) |
| 166 | { |
| 167 | std::fs::write( |
| 168 | workdir.join(format!("queue/{}.bin", test_case.metadata.id)), |
| 169 | &test_case.data.to_bytes(), |
| 170 | )?; |
| 171 | |
| 172 | if let Some(blocks) = test_case.blocks.as_ref() { |
| 173 | use std::io::Write; |
| 174 | |
| 175 | let path = workdir.join(format!("queue/{}.coverage.txt", test_case.metadata.id)); |
| 176 | let mut output = std::io::BufWriter::new( |
| 177 | std::fs::File::create(&path) |
| 178 | .with_context(|| format!("failed to create: {}", path.display()))?, |
| 179 | ); |
| 180 | for addr in blocks { |
| 181 | writeln!(output, "{addr:#x}")?; |
| 182 | } |
| 183 | } |
| 184 | } |
| 185 | |
| 186 | // Save metadata |
| 187 | let testcases: Vec<_> = self.test_cases.iter().map(|x| x.metadata.clone()).collect(); |
| 188 | std::fs::write(workdir.join("testcases.json"), serde_json::ser::to_vec(&testcases)?)?; |
| 189 | std::fs::write(workdir.join("metadata.json"), serde_json::ser::to_vec(&self.metadata)?)?; |
| 190 | |
| 191 | self.last_save_cases = self.test_cases.len(); |
| 192 | self.last_save_time = Instant::now(); |
| 193 | Ok(()) |
| 194 | } |
| 195 | |
| 196 | /// Replace an input in the input corpus with a new version. |
| 197 | pub fn replace_input(&mut self, id: InputId, state: &State) { |
no test coverage detected