Skip to content

Commit

Permalink
put fuzz in same workspace!
Browse files Browse the repository at this point in the history
  • Loading branch information
cosmicexplorer committed Aug 13, 2024
1 parent 2c32f8a commit 886c8d4
Show file tree
Hide file tree
Showing 4 changed files with 148 additions and 59 deletions.
15 changes: 12 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,17 @@ rustdoc-args = ["--cfg", "docsrs"]
members = [
".",
"cli",
"fuzz",
]
default-members = [
".",
]
resolver = "2"

[workspace.dependencies]
arbitrary = { version = "1.3.2", features = ["derive"] }
time = { version = "0.3.36", default-features = false }
zip = { path = "." }
zip = { path = ".", default-features = false }

[dependencies]
aes = { version = "0.8.4", optional = true }
Expand Down Expand Up @@ -65,7 +67,7 @@ lzma-rs = { version = "0.3.0", default-features = false, optional = true }
crossbeam-utils = "0.8.20"

[target.'cfg(fuzzing)'.dependencies]
arbitrary = { version = "1.3.2", features = ["derive"] }
arbitrary.workspace = true

[dev-dependencies]
bencher = "0.1.5"
Expand Down Expand Up @@ -117,5 +119,12 @@ harness = false
# Reduce the size of the zip-cli binary.
[profile.release]
strip = true
lto = true
# This is necessary for fuzzing, which can only use dev or release profiles, and breaks if LTO
# is specified.
lto = false
opt-level = "z"

[profile.release-lto]
inherits = "release"
# This slightly reduces the size of the output binary.
lto = true
18 changes: 14 additions & 4 deletions cli/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
[package]
name = "zip-cli"
version = "0.0.0"
version = "0.0.1"
authors = [
"Danny McClanahan <[email protected]>",
]
license = "MIT"
repository = "https://github.com/zip-rs/zip2.git"
keywords = ["zip", "archive", "compression", "cli"]
categories = ["command-line-utilities", "compression", "filesystem", "development-tools::build-utils"]
rust-version = "1.73.0"
# Keep this up to date with clap!
rust-version = "1.74.0"
description = """
Binary for creation and manipulation of zip files.
"""
Expand All @@ -18,7 +19,16 @@ edition = "2021"
name = "zip-cli"

[dependencies]
zip.workspace = true

clap = { version = "4.5.15", features = ["derive"] }
eyre = "0.6"

[dependencies.zip]
workspace = true
features = [
"bzip2",
"deflate64",
"deflate",
"lzma",
"zstd",
"xz",
]
12 changes: 3 additions & 9 deletions fuzz/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,17 @@ edition = "2018"
cargo-fuzz = true

[dependencies]
zip.workspace = true

libfuzzer-sys = "0.4"
arbitrary = { version = "1.3.2", features = ["derive"] }
arbitrary.workspace = true
replace_with = "0.1.7"
tikv-jemallocator = "0.6.0"

[dependencies.zip]
path = ".."
default-features = false

[features]
zip_defaults = ["zip/default"]
default = ["zip_defaults"]

# Prevent this from interfering with workspaces
[workspace]
members = ["."]

[[bin]]
name = "fuzz_read"
path = "fuzz_targets/fuzz_read.rs"
Expand Down
162 changes: 119 additions & 43 deletions fuzz/fuzz_targets/fuzz_write.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
#![no_main]

use arbitrary::Arbitrary;
use core::fmt::{Debug};
use core::fmt::Debug;
use libfuzzer_sys::fuzz_target;
use replace_with::replace_with_or_abort;
use std::fmt::{Arguments, Formatter, Write};
use std::io::{Cursor, Seek, SeekFrom};
use std::io::Write as IoWrite;
use std::io::{Cursor, Seek, SeekFrom};
use std::path::PathBuf;
use tikv_jemallocator::Jemalloc;
use zip::result::{ZipError, ZipResult};
Expand Down Expand Up @@ -93,22 +93,36 @@ fn do_operation<'k>(
flush_on_finish_file: bool,
files_added: &mut usize,
stringifier: &mut impl Write,
panic_on_error: bool
panic_on_error: bool,
) -> Result<(), Box<dyn std::error::Error>> {
writer.set_flush_on_finish_file(flush_on_finish_file);
let FileOperation { basic, mut path, reopen} = operation;
let FileOperation {
basic,
mut path,
reopen,
} = operation;
match basic {
BasicFileOperation::WriteNormalFile {
contents, mut options, ..
contents,
mut options,
..
} => {
let uncompressed_size = contents.iter().map(|chunk| chunk.len()).sum::<usize>();
if uncompressed_size >= u32::MAX as usize {
options = options.large_file(true);
}
if options == FullFileOptions::default() {
writeln!(stringifier, "writer.start_file_from_path({:?}, Default::default())?;", path)?;
writeln!(
stringifier,
"writer.start_file_from_path({:?}, Default::default())?;",
path
)?;
} else {
writeln!(stringifier, "writer.start_file_from_path({:?}, {:?})?;", path, options)?;
writeln!(
stringifier,
"writer.start_file_from_path({:?}, {:?})?;",
path, options
)?;
}
writer.start_file_from_path(&*path, options)?;
for chunk in contents.iter() {
Expand All @@ -118,12 +132,20 @@ fn do_operation<'k>(
*files_added += 1;
}
BasicFileOperation::WriteDirectory(options) => {
writeln!(stringifier, "writer.add_directory_from_path(&{:?}, {:?})?;", path, options)?;
writeln!(
stringifier,
"writer.add_directory_from_path(&{:?}, {:?})?;",
path, options
)?;
writer.add_directory_from_path(&*path, options.to_owned())?;
*files_added += 1;
}
BasicFileOperation::WriteSymlinkWithTarget { target, options } => {
writeln!(stringifier, "writer.add_symlink_from_path(&{:?}, {:?}, {:?});", path, target, options)?;
writeln!(
stringifier,
"writer.add_symlink_from_path(&{:?}, {:?}, {:?});",
path, target, options
)?;
writer.add_symlink_from_path(&*path, target, options.to_owned())?;
*files_added += 1;
}
Expand All @@ -132,8 +154,20 @@ fn do_operation<'k>(
return Ok(());
};
deduplicate_paths(&mut path, &base_path);
do_operation(writer, *base, false, flush_on_finish_file, files_added, stringifier, panic_on_error)?;
writeln!(stringifier, "writer.shallow_copy_file_from_path({:?}, {:?});", base_path, path)?;
do_operation(
writer,
*base,
false,
flush_on_finish_file,
files_added,
stringifier,
panic_on_error,
)?;
writeln!(
stringifier,
"writer.shallow_copy_file_from_path({:?}, {:?});",
base_path, path
)?;
writer.shallow_copy_file_from_path(&*base_path, &*path)?;
*files_added += 1;
}
Expand All @@ -142,38 +176,65 @@ fn do_operation<'k>(
return Ok(());
};
deduplicate_paths(&mut path, &base_path);
do_operation(writer, *base, false, flush_on_finish_file, files_added, stringifier, panic_on_error)?;
writeln!(stringifier, "writer.deep_copy_file_from_path({:?}, {:?});", base_path, path)?;
do_operation(
writer,
*base,
false,
flush_on_finish_file,
files_added,
stringifier,
panic_on_error,
)?;
writeln!(
stringifier,
"writer.deep_copy_file_from_path({:?}, {:?});",
base_path, path
)?;
writer.deep_copy_file_from_path(&*base_path, path)?;
*files_added += 1;
}
BasicFileOperation::MergeWithOtherFile { operations, initial_junk } => {
BasicFileOperation::MergeWithOtherFile {
operations,
initial_junk,
} => {
if initial_junk.is_empty() {
writeln!(stringifier, "let sub_writer = {{\n\
let mut writer = ZipWriter::new(Cursor::new(Vec::new()));")?;
writeln!(
stringifier,
"let sub_writer = {{\n\
let mut writer = ZipWriter::new(Cursor::new(Vec::new()));"
)?;
} else {
writeln!(stringifier,
"let sub_writer = {{\n\
writeln!(
stringifier,
"let sub_writer = {{\n\
let mut initial_junk = Cursor::new(vec!{:?});\n\
initial_junk.seek(SeekFrom::End(0))?;
let mut writer = ZipWriter::new(initial_junk);", initial_junk)?;
let mut writer = ZipWriter::new(initial_junk);",
initial_junk
)?;
}
let mut initial_junk = Cursor::new(initial_junk.into_vec());
initial_junk.seek(SeekFrom::End(0))?;
let mut other_writer = zip::ZipWriter::new(initial_junk);
let mut inner_files_added = 0;
operations.into_vec().into_iter().for_each(|(operation, abort)| {
let _ = do_operation(
&mut other_writer,
operation,
abort,
false,
&mut inner_files_added,
stringifier,
panic_on_error
);
});
writeln!(stringifier, "writer\n}};\nwriter.merge_archive(sub_writer.finish_into_readable()?)?;")?;
operations
.into_vec()
.into_iter()
.for_each(|(operation, abort)| {
let _ = do_operation(
&mut other_writer,
operation,
abort,
false,
&mut inner_files_added,
stringifier,
panic_on_error,
);
});
writeln!(
stringifier,
"writer\n}};\nwriter.merge_archive(sub_writer.finish_into_readable()?)?;"
)?;
writer.merge_archive(other_writer.finish_into_readable()?)?;
*files_added += inner_files_added;
}
Expand All @@ -193,15 +254,19 @@ fn do_operation<'k>(
match reopen {
ReopenOption::DoNotReopen => {
writeln!(stringifier, "writer")?;
return Ok(())
},
return Ok(());
}
ReopenOption::ViaFinish => {
let old_comment = writer.get_raw_comment().to_owned();
writeln!(stringifier, "let mut writer = ZipWriter::new_append(writer.finish()?)?;")?;
writeln!(
stringifier,
"let mut writer = ZipWriter::new_append(writer.finish()?)?;"
)?;
replace_with_or_abort(writer, |old_writer: zip::ZipWriter<Cursor<Vec<u8>>>| {
(|| -> ZipResult<zip::ZipWriter<Cursor<Vec<u8>>>> {
zip::ZipWriter::new_append(old_writer.finish()?)
})().unwrap_or_else(|_| {
})()
.unwrap_or_else(|_| {
if panic_on_error {
panic!("Failed to create new ZipWriter")
}
Expand All @@ -214,11 +279,15 @@ fn do_operation<'k>(
}
ReopenOption::ViaFinishIntoReadable => {
let old_comment = writer.get_raw_comment().to_owned();
writeln!(stringifier, "let mut writer = ZipWriter::new_append(writer.finish()?)?;")?;
writeln!(
stringifier,
"let mut writer = ZipWriter::new_append(writer.finish()?)?;"
)?;
replace_with_or_abort(writer, |old_writer| {
(|| -> ZipResult<zip::ZipWriter<Cursor<Vec<u8>>>> {
zip::ZipWriter::new_append(old_writer.finish()?)
})().unwrap_or_else(|_| {
})()
.unwrap_or_else(|_| {
if panic_on_error {
panic!("Failed to create new ZipWriter")
}
Expand All @@ -231,7 +300,7 @@ fn do_operation<'k>(
Ok(())
}

impl <'k> FuzzTestCase<'k> {
impl<'k> FuzzTestCase<'k> {
fn execute(self, stringifier: &mut impl Write, panic_on_error: bool) -> ZipResult<()> {
let mut initial_junk = Cursor::new(self.initial_junk.into_vec());
initial_junk.seek(SeekFrom::End(0))?;
Expand All @@ -253,7 +322,7 @@ impl <'k> FuzzTestCase<'k> {
self.flush_on_finish_file,
&mut files_added,
stringifier,
panic_on_error
panic_on_error,
);
}
if final_reopen {
Expand All @@ -265,14 +334,21 @@ impl <'k> FuzzTestCase<'k> {
}
}

impl <'k> Debug for FuzzTestCase<'k> {
impl<'k> Debug for FuzzTestCase<'k> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
if self.initial_junk.is_empty() {
writeln!(f, "let mut writer = ZipWriter::new(Cursor::new(Vec::new()));")?;
writeln!(
f,
"let mut writer = ZipWriter::new(Cursor::new(Vec::new()));"
)?;
} else {
writeln!(f, "let mut initial_junk = Cursor::new(vec!{:?});\n\
writeln!(
f,
"let mut initial_junk = Cursor::new(vec!{:?});\n\
initial_junk.seek(SeekFrom::End(0))?;\n\
let mut writer = ZipWriter::new(initial_junk);", &self.initial_junk)?;
let mut writer = ZipWriter::new(initial_junk);",
&self.initial_junk
)?;
}
let _ = self.clone().execute(f, false);
Ok(())
Expand Down

0 comments on commit 886c8d4

Please sign in to comment.