Fuzzing comparativo strumenti Rust paralleli
In precedenza ho scritto su come possiamo usare la "concorrenza senza paura" di Rust , ottenendo uno strumento chiamato ripunzip. (Ecco alcuni risultati delle prestazioni ).
Come possiamo essere sicuri che si comporti allo stesso modo di un unzip non parallelo, regolare? Anche in circostanze impreviste?
La risposta: fuzzing comparativo . Il fuzzing è normalmente una tecnica usata per trovare bug di sicurezza — ecco una ricetta su come puoi usarlo per cercare bug nel codice non sicuro di Rust — ma puoi anche usarlo per verificare che due implementazioni si comportino allo stesso modo — fuzzing comparativo.
È una buona soluzione per il caso in cui stiamo cercando di creare una versione più veloce di uno strumento esistente e il fuzzing sembra essere piuttosto divertente, specialmente in Rust dove c'è il meraviglioso arbitrary crate .
Ecco il piano:
- Descrivi tutti gli input a
ripunzip, incluso il file zip, utilizzando ilarbitrarycrate - Esegui
ripunzipin base a tali input - Decomprimi anche lo stesso file usando un normale filetto singolo
zip-rs - Verifica che entrambi abbiano avuto successo o che entrambi abbiano fallito
- Confronta la directory decompressa. Se è diverso, schiantati!
Ecco il fuzzer con cui siamo finiti . Innanzitutto, diamo un'occhiata ai dati di input:
#[derive(arbitrary::Arbitrary, Eq, PartialEq, Hash, Debug, Clone)]
struct ZipMemberFilename(/* details omitted... described later */);
#[derive(Eq, PartialEq, Hash, Debug, Clone, Copy, arbitrary::Arbitrary)]
enum CompressionMethod {
Stored,
Deflated,
Bzip2,
Zstd,
}
#[derive(arbitrary::Arbitrary, Debug, Clone)]
struct Inputs {
// HashMap to ensure unique filenames in zip
zip_members: HashMap<ZipMemberFilename, Vec<u8>>,
compression_method: CompressionMethod,
single_threaded: bool,
}
Deriva Arbitrary, il che significa che il codice viene generato per costruire questa struttura da un blob binario opaco. Quei BLOB binari sono generati da libfuzzer e, soprattutto, vengono modificati e modificati nuovamente per esplorare gradualmente quanto più possibile del programma, in base alle indicazioni sulla copertura.
Abbiamo alcuni input piuttosto complessi lì - HashMap, vettori ed enum personalizzati. Arbitraryè abbastanza intelligente da generarli tutti.
Ora, il fuzzer stesso è essenzialmente banale: creiamo letteralmente solo lo zip, lo decomprimiamo due volte e confrontiamo gli output.
fuzz_target!(|input: Inputs| {
let progress_reporter = ripunzip::NullProgressReporter;
let tempdir = tempfile::tempdir().unwrap();
let output_directory = tempdir.path().join("out_ripunzip");
let output_directory_unzip = tempdir.path().join("out_unzip");
std::fs::create_dir_all(&output_directory).unwrap();
let options = ripunzip::UnzipOptions {
single_threaded: input.single_threaded,
output_directory: Some(output_directory.clone()),
};
let zipfile = tempdir.path().join("file.zip");
let mut zip_data = Vec::new();
create_zip(&mut zip_data, &input.zip_members, input.compression_method);
let mut file = std::fs::File::create(&zipfile).unwrap();
file.write_all(&zip_data).unwrap();
drop(file);
let file = std::fs::File::open(&zipfile).unwrap();
let ripunzip_result: Result<(), anyhow::Error> = (|| {
let ripunzip = ripunzip::UnzipEngine::for_file(file, options, progress_reporter)?;
ripunzip.unzip()
})();
let unziprs_result = unzip_with_zip_rs(&zipfile, &output_directory_unzip);
match unziprs_result {
Err(err) => {
if ripunzip_result.is_ok() {
panic!("ripunzip succeeded; plain unzip gave {:?}", err)
}
}
Ok(_) => {
ripunzip_result.unwrap();
let ripunzip_paths = recursive_lsdir(&output_directory);
let unzip_paths = recursive_lsdir(&output_directory_unzip);
// We do not currently compare the actual zip file contents.
// It seems unlikely that this would be a failure mode where
// ripunzip would differ from zip-rs.
assert_eq!(ripunzip_paths, unzip_paths);
}
}
});
fn recursive_lsdir(dir: &Path) -> HashSet<std::path::PathBuf> {
walkdir::WalkDir::new(dir)
.into_iter()
.filter_map(|e| e.ok())
.map(|e| e.path().strip_prefix(dir).unwrap().to_path_buf())
.collect()
}
// Create a zip file from zip_members into output,
// using the given compression mode. Details omitted.
fn create_zip(output: &mut Vec<u8>, zip_members: &HashMap<ZipMemberFilename, Vec<u8>>, compression_method: CompressionMethod) {
// ...
}
/// Errors that can occur with a regular zip-rs unzip, details omitted
#[derive(Debug)]
enum ZipRsError {
// ...
}
/// Unzip the content with standard zip-rs.
fn unzip_with_zip_rs(zipfile_path: &Path, dest_path: &Path) -> Result<(), ZipRsError> {
// ...
}
#[derive(arbitrary::Arbitrary, Debug, Clone, strum::Display, Hash, Eq, PartialEq)]
enum FilenameSegment {
Fish,
A,
#[strum(serialize = "b")]
B,
#[strum(serialize = "31")]
ThirtyOne,
#[strum(serialize = "_c")]
C,
D,
#[strum(serialize = "e.txt")]
ETxt,
}
#[derive(arbitrary::Arbitrary, Eq, PartialEq, Hash, Debug, Clone)]
struct ZipMemberFilename(Vec<FilenameSegment>);
impl Into<String> for &ZipMemberFilename {
fn into(self) -> String {
self.0.iter().join("/")
}
}
Cosa succede quando eseguiamo questo? Vediamo questo delizioso output mentre i fuzzer si aggirano intorno alla nostra base di codice.
$ cargo +nightly fuzz run fuzz_ripunzip
Compiling ripunzip v0.2.2 (ripunzip)
Compiling ripunzip-fuzz v0.0.0 (ripunzip/fuzz)
Finished release [optimized] target(s) in 18.06s
Finished release [optimized] target(s) in 0.18s
Running `target/x86_64-apple-darwin/release/fuzz_ripunzip -artifact_prefix=ripunzip/fuzz/artifacts/fuzz_ripunzip/ ripunzip/fuzz/corpus/fuzz_ripunzip`
fuzz_ripunzip(13490,0x7ff85b1088c0) malloc: nano zone abandoned due to inability to preallocate reserved vm space.
INFO: Running with entropic power schedule (0xFF, 100).
INFO: Seed: 3274692728
INFO: Loaded 1 modules (720556 inline 8-bit counters): 720556 [0x107a95260, 0x107b4510c),
INFO: Loaded 1 PC tables (720556 PCs): 720556 [0x107b45110,0x108643bd0),
INFO: 0 files found in ripunzip/fuzz/corpus/fuzz_ripunzip
INFO: -max_len is not provided; libFuzzer will not generate inputs larger than 4096 bytes
INFO: A corpus is not provided, starting from an empty corpus
#2 INITED exec/s: 0 rss: 53Mb
NEW_FUNC[1/171]: 0x105266120 in _$LT$core..iter..adapters..map..Map$LT$I$C$F$GT$$u20$as$u20$core..iter..traits..iterator..Iterator$GT$::fold::h2eed7f9eb6137b14+0x0 (fuzz_ripunzip:x86_64+0x100003120) (BuildId: d85ba98c8ed134a4845c0cff1565ef9632000000200000000100000000000d00)
NEW_FUNC[2/171]: 0x10526abc0 in _$LT$ripunzip..unzip..cloneable_seekable_reader..CloneableSeekableReader$LT$R$GT$$u20$as$u20$std..io..Read$GT$::read::h7325b227d55c68e7+0x0 (fuzz_ripunzip:x86_64+0x100007bc0) (BuildId: d85ba98c8ed134a4845c0cff1565ef9632000000200000000100000000000d00)
#212 NEW cov: 1204 ft: 1177 corp: 2/7b lim: 6 exec/s: 212 rss: 59Mb L: 6/6 MS: 4 ChangeBit-ChangeBit-InsertByte-InsertRepeatedBytes-
#213 NEW cov: 1209 ft: 1182 corp: 3/13b lim: 6 exec/s: 213 rss: 59Mb L: 6/6 MS: 1 ShuffleBytes-
#217 NEW cov: 1210 ft: 1184 corp: 4/18b lim: 6 exec/s: 217 rss: 59Mb L: 5/6 MS: 4 CopyPart-ChangeByte-ShuffleBytes-InsertRepeatedBytes-
NEW_FUNC[1/90]: 0x10526a3b0 in _$LT$std..io..cursor..Cursor$LT$$RF$mut$u20$alloc..vec..Vec$LT$u8$C$A$GT$$GT$$u20$as$u20$std..io..Write$GT$::write::hb0a9a4b62999ace6+0x0 (fuzz_ripunzip:x86_64+0x1000073b0) (BuildId: d85ba98c8ed134a4845c0cff1565ef9632000000200000000100000000000d00)
NEW_FUNC[2/90]: 0x10526ca90 in _$LT$alloc..vec..Vec$LT$T$GT$$u20$as$u20$alloc..vec..spec_from_iter_nested..SpecFromIterNested$LT$T$C$I$GT$$GT$::from_iter::h62629dd53aaca6a9+0x0 (fuzz_ripunzip:x86_64+0x100009a90) (BuildId: d85ba98c8ed134a4845c0cff1565ef9632000000200000000100000000000d00)
#220 NEW cov: 2100 ft: 2235 corp: 5/23b lim: 6 exec/s: 220 rss: 60Mb L: 5/6 MS: 3 CrossOver-ShuffleBytes-InsertRepeatedBytes-
#222 NEW cov: 2101 ft: 2237 corp: 6/29b lim: 6 exec/s: 222 rss: 60Mb L: 6/6 MS: 2 CrossOver-CopyPart-
NEW_FUNC[1/1]: 0x1053ad5c0 in _$LT$alloc..vec..Vec$LT$T$GT$$u20$as$u20$alloc..vec..spec_from_iter_nested..SpecFromIterNested$LT$T$C$I$GT$$GT$::from_iter::h14e3944acd671fa2+0x0 (fuzz_ripunzip:x86_64+0x10014a5c0) (BuildId: d85ba98c8ed134a4845c0cff1565ef9632000000200000000100000000000d00)
#231 NEW cov: 2108 ft: 2245 corp: 7/35b lim: 6 exec/s: 231 rss: 60Mb L: 6/6 MS: 4 CopyPart-ShuffleBytes-ShuffleBytes-CopyPart-
NEW_FUNC[1/12]: 0x1052d2580 in core::ptr::drop_in_place$LT$fuzz_ripunzip..ZipRsError$GT$::h864830fa1576e5d5+0x0 (fuzz_ripunzip:x86_64+0x10006f580) (BuildId: d85ba98c8ed134a4845c0cff1565ef9632000000200000000100000000000d00)
NEW_FUNC[2/12]: 0x1053f7e70 in core::ptr::drop_in_place$LT$anyhow..error..ErrorImpl$LT$anyhow..error..ContextError$LT$core..mem..manually_drop..ManuallyDrop$LT$$RF$str$GT$$C$std..io..error..Error$GT$$GT$$GT$::he14691a68652570b+0x0 (fuzz_ripunzip:x86_64+0x100194e70) (BuildId: d85ba98c8ed134a4845c0cff1565ef9632000000200000000100000000000d00)
#235 NEW cov: 2193 ft: 2373 corp: 8/41b lim: 6 exec/s: 235 rss: 60Mb L: 6/6 MS: 4 InsertRepeatedBytes-CopyPart-CopyPart-ChangeByte-
#241 REDUCE cov: 2193 ft: 2373 corp: 8/40b lim: 6 exec/s: 241 rss: 61Mb L: 5/6 MS: 1 EraseBytes-
#244 NEW cov: 2193 ft: 2375 corp: 9/45b lim: 6 exec/s: 244 rss: 61Mb L: 5/6 MS: 3 ChangeByte-EraseBytes-ShuffleBytes-
#252 NEW cov: 2199 ft: 2394 corp: 10/51b lim: 6 exec/s: 252 rss: 61Mb L: 6/6 MS: 3 CrossOver-InsertByte-InsertRepeatedBytes-
#256 NEW cov: 2199 ft: 2398 corp: 11/56b lim: 6 exec/s: 256 rss: 61Mb L: 5/6 MS: 4 ChangeBit-CrossOver-CrossOver-InsertRepeatedBytes-
#273 NEW cov: 2199 ft: 2399 corp: 12/62b lim: 6 exec/s: 273 rss: 62Mb L: 6/6 MS: 2 ChangeBit-InsertByte-
#274 NEW cov: 2199 ft: 2401 corp: 13/68b lim: 6 exec/s: 274 rss: 62Mb L: 6/6 MS: 1 ChangeByte-
#282 NEW cov: 2199 ft: 2402 corp: 14/74b lim: 6 exec/s: 282 rss: 62Mb L: 6/6 MS: 3 ShuffleBytes-CrossOver-ChangeBinInt-
#285 NEW cov: 2205 ft: 2463 corp: 15/80b lim: 6 exec/s: 285 rss: 62Mb L: 6/6 MS: 3 CMP-CopyPart-CMP- DE: " \000\000\000"-"\001\000\000\005"-
#298 NEW cov: 2205 ft: 2465 corp: 16/86b lim: 6 exec/s: 298 rss: 63Mb L: 6/6 MS: 3 ChangeBit-ChangeBinInt-ChangeBinInt-
NEW_FUNC[1/1]: 0x1074d09b0 in _$LT$u8$u20$as$u20$arbitrary..Arbitrary$GT$::arbitrary::hbd4728a44a66213a+0x0 (fuzz_ripunzip:x86_64+0x10226d9b0) (BuildId: d85ba98c8ed134a4845c0cff1565ef9632000000200000000100000000000d00)
#314 NEW cov: 2219 ft: 2479 corp: 17/92b lim: 6 exec/s: 314 rss: 63Mb L: 6/6 MS: 1 ChangeByte-
#340 NEW cov: 2231 ft: 2499 corp: 18/98b lim: 6 exec/s: 340 rss: 64Mb L: 6/6 MS: 1 ChangeBinInt-
#347 NEW cov: 2232 ft: 2502 corp: 19/104b lim: 6 exec/s: 347 rss: 64Mb L: 6/6 MS: 2 ChangeBinInt-ChangeBit-
NEW_FUNC[1/27]: 0x1053a3620 in rayon_core::join::join_context::_$u7b$$u7b$closure$u7d$$u7d$::heeeee28ce9473e59+0x0 (fuzz_ripunzip:x86_64+0x100140620) (BuildId: d85ba98c8ed134a4845c0cff1565ef9632000000200000000100000000000d00)
NEW_FUNC[2/27]: 0x1053a5d20 in rayon_core::sleep::Sleep::new_jobs::hfc61bcd28f9a7e21+0x0 (fuzz_ripunzip:x86_64+0x100142d20) (BuildId: d85ba98c8ed134a4845c0cff1565ef9632000000200000000100000000000d00)
#379 NEW cov: 2447 ft: 3413 corp: 20/110b lim: 6 exec/s: 379 rss: 65Mb L: 6/6 MS: 1 ChangeBinInt-
#384 NEW cov: 2450 ft: 3427 corp: 21/116b lim: 6 exec/s: 384 rss: 65Mb L: 6/6 MS: 5 ChangeByte-CopyPart-ChangeBit-CopyPart-PersAutoDict- DE: "\001\000\000\005"-
NEW_FUNC[1/1]: 0x105285c50 in std::thread::local::fast::Key$LT$T$GT$::try_initialize::h078871c80893dca2+0x0 (fuzz_ripunzip:x86_64+0x100022c50) (BuildId: d85ba98c8ed134a4845c0cff1565ef9632000000200000000100000000000d00)
#387 NEW cov: 2469 ft: 3446 corp: 22/122b lim: 6 exec/s: 387 rss: 65Mb L: 6/6 MS: 3 CrossOver-ChangeByte-CrossOver-
#388 NEW cov: 2470 ft: 3449 corp: 23/128b lim: 6 exec/s: 388 rss: 65Mb L: 6/6 MS: 1 ChangeBinInt-
NEW_FUNC[1/3]: 0x1053b3ea0 in crossbeam_deque::deque::Worker$LT$T$GT$::pop::h027afe55d57c8358+0x0 (fuzz_ripunzip:x86_64+0x100150ea0) (BuildId: d85ba98c8ed134a4845c0cff1565ef9632000000200000000100000000000d00)
NEW_FUNC[2/3]: 0x1053b4b30 in crossbeam_deque::deque::Stealer$LT$T$GT$::steal::h20410f4e42e0f324+0x0 (fuzz_ripunzip:x86_64+0x100151b30) (BuildId: d85ba98c8ed134a4845c0cff1565ef9632000000200000000100000000000d00)
#394 NEW cov: 2497 ft: 3598 corp: 24/134b lim: 6 exec/s: 394 rss: 65Mb L: 6/6 MS: 1 ChangeBit-
#400 NEW cov: 2497 ft: 3602 corp: 25/140b lim: 6 exec/s: 400 rss: 66Mb L: 6/6 MS: 1 CopyPart-
#411 NEW cov: 2502 ft: 3618 corp: 26/146b lim: 6 exec/s: 411 rss: 66Mb L: 6/6 MS: 1 InsertByte-
#439 NEW cov: 2503 ft: 3619 corp: 27/152b lim: 6 exec/s: 439 rss: 67Mb L: 6/6 MS: 3 ChangeBit-ChangeBinInt-ShuffleBytes-
#462 NEW cov: 2504 ft: 3621 corp: 28/158b lim: 6 exec/s: 462 rss: 68Mb L: 6/6 MS: 3 ChangeBinInt-ShuffleBytes-ShuffleBytes-
#463 NEW cov: 2504 ft: 3624 corp: 29/164b lim: 6 exec/s: 463 rss: 68Mb L: 6/6 MS: 1 CrossOver-
#464 NEW cov: 2504 ft: 3630 corp: 30/170b lim: 6 exec/s: 464 rss: 68Mb L: 6/6 MS: 1 ChangeBit-
#480 NEW cov: 2505 ft: 3631 corp: 31/176b lim: 6 exec/s: 480 rss: 68Mb L: 6/6 MS: 1 CrossOver-
#486 NEW cov: 2505 ft: 3636 corp: 32/182b lim: 6 exec/s: 486 rss: 68Mb L: 6/6 MS: 1 ChangeBinInt-
#487 NEW cov: 2505 ft: 3637 corp: 33/188b lim: 6 exec/s: 487 rss: 68Mb L: 6/6 MS: 1 CopyPart-
#527 NEW cov: 2505 ft: 3641 corp: 34/194b lim: 6 exec/s: 527 rss: 69Mb L: 6/6 MS: 5 ChangeBinInt-CrossOver-CopyPart-ChangeBinInt-PersAutoDict- DE: "\001\000\000\005"-
NEW_FUNC[1/1]: 0x1052de9a0 in core::iter::traits::double_ended::DoubleEndedIterator::try_rfold::hcf0f30052624299f+0x0 (fuzz_ripunzip:x86_64+0x10007b9a0) (BuildId: d85ba98c8ed134a4845c0cff1565ef9632000000200000000100000000000d00)
#538 NEW cov: 2535 ft: 3675 corp: 35/200b lim: 6 exec/s: 538 rss: 70Mb L: 6/6 MS: 1 CopyPart-
Dopo aver digitato il paragrafo precedente, ora vengono esplorati 3795 blocchi di codice.
Alla fine si stabilizza. È stranamente affascinante.
Allora, ha funzionato? Ha riscontrato problemi?
SÌ! Subito. Per esempio:
$ RUST_BACKTRACE=1 cargo +nightly fuzz run fuzz_ripunzip
Finished release [optimized] target(s) in 0.21s
Finished release [optimized] target(s) in 0.20s
Running `target/x86_64-apple-darwin/release/fuzz_ripunzip -artifact_prefix=ripunzip/fuzz/artifacts/fuzz_ripunzip/ ripunzip/fuzz/corpus/fuzz_ripunzip`
fuzz_ripunzip(14468,0x7ff85b1088c0) malloc: nano zone abandoned due to inability to preallocate reserved vm space.
INFO: Running with entropic power schedule (0xFF, 100).
INFO: Seed: 3659845534
INFO: Loaded 1 modules (719987 inline 8-bit counters): 719987 [0x10c8e5fe0, 0x10c995c53),
INFO: Loaded 1 PC tables (719987 PCs): 719987 [0x10c995c58,0x10d492388),
INFO: 0 files found in ripunzip/fuzz/corpus/fuzz_ripunzip
INFO: -max_len is not provided; libFuzzer will not generate inputs larger than 4096 bytes
INFO: A corpus is not provided, starting from an empty corpus
#2 INITED exec/s: 0 rss: 53Mb
WARNING: no interesting inputs were found so far. Is the code instrumented for coverage?
This may also happen if the target rejected all inputs we tried so far
thread '<unnamed>' panicked at 'attempt to subtract with overflow', ripunzip/src/unzip/cloneable_seekable_reader.rs:93:17
stack backtrace:
0: rust_begin_unwind
at /rustc/ec56537c4325ce5b798fc3628cbdd48ba4949ae5/library/std/src/panicking.rs:575:5
1: core::panicking::panic_fmt
at /rustc/ec56537c4325ce5b798fc3628cbdd48ba4949ae5/library/core/src/panicking.rs:64:14
2: core::panicking::panic
at /rustc/ec56537c4325ce5b798fc3628cbdd48ba4949ae5/library/core/src/panicking.rs:111:5
3: <ripunzip::unzip::cloneable_seekable_reader::CloneableSeekableReader<R> as std::io::Seek>::seek
4: zip::read::<impl zip::read::zip_archive::ZipArchive<R>>::get_directory_counts
5: zip::read::<impl zip::read::zip_archive::ZipArchive<R>>::new
6: ripunzip::unzip::UnzipEngine<P>::for_file
7: fuzz_ripunzip::_::run
8: _rust_fuzzer_test_input
9: std::panicking::try::do_call
10: ___rust_try
11: _LLVMFuzzerTestOneInput
12: __ZN6fuzzer6Fuzzer15ExecuteCallbackEPKhm
13: __ZN6fuzzer6Fuzzer6RunOneEPKhmbPNS_9InputInfoEbPb
14: __ZN6fuzzer6Fuzzer16MutateAndTestOneEv
15: __ZN6fuzzer6Fuzzer4LoopERNSt3__16vectorINS_9SizedFileENS1_9allocatorIS3_EEEE
16: __ZN6fuzzer12FuzzerDriverEPiPPPcPFiPKhmE
17: _main
18: <unknown>
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
==14468== ERROR: libFuzzer: deadly signal
#0 0x10e2a6185 in __sanitizer_print_stack_trace+0x35 (librustc-nightly_rt.asan.dylib:x86_64h+0x53185) (BuildId: d21cf6fbe4db36c3a2772a5990be16c5240000001000000000070a0000030c00)
#1 0x10c2c1d1a in fuzzer::PrintStackTrace()+0x2a (fuzz_ripunzip:x86_64+0x102205d1a) (BuildId: 52587ab92ee03de78cc50b187a499a5332000000200000000100000000000d00)
#2 0x10c2b49e3 in fuzzer::Fuzzer::CrashCallback()+0x43 (fuzz_ripunzip:x86_64+0x1021f89e3) (BuildId: 52587ab92ee03de78cc50b187a499a5332000000200000000100000000000d00)
#3 0x7ff817802c1c in _sigtramp+0x1c (libsystem_platform.dylib:x86_64+0x3c1c) (BuildId: f314b62b98f43a7c82968739f8b6855a240000001000000000010d0000010d00)
NOTE: libFuzzer has rudimentary signal handlers.
Combine libFuzzer with AddressSanitizer or similar for better crash reports.
SUMMARY: libFuzzer: deadly signal
MS: 1 InsertRepeatedBytes-; base unit: adc83b19e793491b1c6ea0fd8b46cd9f32e592fc
0xa,0x0,0x0,0x0,0x0,0x0,
\012\000\000\000\000\000
artifact_prefix='ripunzip/fuzz/artifacts/fuzz_ripunzip/'; Test unit written to ripunzip/fuzz/artifacts/fuzz_ripunzip/crash-fd324ba7ec17e3df5e8735319dc70009a81c1b6c
Base64: CgAAAAAA
────────────────────────────────────────────────────────────────────────────────
Failing input:
artifacts/fuzz_ripunzip/crash-fd324ba7ec17e3df5e8735319dc70009a81c1b6c
Output of `std::fmt::Debug`:
Inputs {
zip_members: {},
compression_method: Stored,
single_threaded: false,
}
Reproduce with:
cargo fuzz run fuzz_ripunzip artifacts/fuzz_ripunzip/crash-fd324ba7ec17e3df5e8735319dc70009a81c1b6c
Minimize test case with:
cargo fuzz tmin fuzz_ripunzip artifacts/fuzz_ripunzip/crash-fd324ba7ec17e3df5e8735319dc70009a81c1b6c
────────────────────────────────────────────────────────────────────────────────
Error: Fuzz target exited with exit status: 77
Stack backtrace:
0: std::backtrace::Backtrace::create
1: std::backtrace::Backtrace::capture
2: anyhow::error::<impl anyhow::Error>::msg
3: cargo_fuzz::project::FuzzProject::exec_fuzz
4: <cargo_fuzz::options::run::Run as cargo_fuzz::RunCommand>::run_command
5: cargo_fuzz::main
6: std::sys_common::backtrace::__rust_begin_short_backtrace
7: std::rt::lang_start::{{closure}}
8: std::rt::lang_start_internal
9: _main
10: <unknown>
Ha anche individuato:
- a volte più thread correvano per creare directory principali dei membri che stavano decomprimendo.
- abbiamo preso decisioni diverse per quanto riguarda i nomi di file che terminano con
/- mi sono allineato al comportamento di zip-rs qui
PS ora sono stati esplorati 4359 blocchi di codice

![Che cos'è un elenco collegato, comunque? [Parte 1]](https://post.nghiatu.com/assets/images/m/max/724/1*Xokk6XOjWyIGCBujkJsCzQ.jpeg)



































