Outils comparatifs de fuzzing parallèle Rust
J'ai déjà écrit sur la façon dont nous pouvons utiliser la "concurrence sans peur" de Rust , résultant en un outil appelé ripunzip. (Voici quelques résultats de performances ).
Comment pouvons-nous être sûrs qu'il se comporte de la même manière qu'un décompression régulier non parallèle ? Même dans des circonstances imprévues ?
La réponse : le fuzzing comparatif . Le fuzzing est normalement une technique utilisée pour trouver des bogues de sécurité - voici une recette pour savoir comment vous pouvez l'utiliser pour rechercher des bogues dans le code non sécurisé de Rust - mais vous pouvez également l'utiliser pour vérifier que deux implémentations se comportent de la même manière - fuzzing comparatif.
C'est un bon choix pour le cas où nous essayons de créer une version plus rapide d'un outil existant, et le fuzzing s'avère assez amusant — surtout dans Rust où il y a la merveilleuse arbitrary crate .
Voici le planning :
- Décrivez toutes les entrées de
ripunzip, y compris le fichier zip, en utilisant learbitrarycrate - Exécuter
ripunzipen fonction de ces entrées - Décompressez également le même fichier à l'aide d'un simple thread
zip-rs - Vérifiez qu'ils ont tous les deux réussi ou échoué
- Comparez le répertoire décompressé. Si c'est différent, crash !
Voici le fuzzer avec lequel nous nous sommes retrouvés . Examinons d'abord les données d'entrée :
#[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,
}
Il dérive Arbitrary, ce qui signifie que du code est généré pour construire cette structure à partir d'un blob binaire opaque. Ces blobs binaires sont générés par libfuzzer , et - surtout - ils sont modifiés et ré-modifiés pour explorer progressivement autant du programme que possible, sur la base des conseils de couverture.
Nous avons ici des entrées assez complexes - HashMap, des vecteurs et des énumérations personnalisées. Arbitraryest assez intelligent pour les générer tous.
Maintenant, le fuzzer lui-même est essentiellement trivial - nous créons littéralement le zip, le décompressons deux fois et comparons les sorties.
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("/")
}
}
Que se passe-t-il lorsque nous exécutons cela ? Nous voyons cette sortie délicieuse alors que le fuzzer furet autour de notre base de code.
$ 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-
Après avoir tapé le paragraphe ci-dessus, il est maintenant exploré 3795 blocs de code.
Finalement, ça plafonne. C'est étrangement fascinant.
Alors, ça a marché ? A-t-il trouvé des problèmes ?
Oui! Immédiatement. Par exemple:
$ 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>
Il a également repéré :
- parfois, plusieurs threads se sont précipités pour créer des répertoires parents des membres qu'ils décompressaient.
- nous avons pris différentes décisions concernant les noms de fichiers se terminant par
/- je me suis aligné sur le comportement zip-rs ici
PS c'est maintenant exploré 4359 blocs de code
![Qu'est-ce qu'une liste liée, de toute façon? [Partie 1]](https://post.nghiatu.com/assets/images/m/max/724/1*Xokk6XOjWyIGCBujkJsCzQ.jpeg)



































