diff --git a/Cargo.lock b/Cargo.lock index 8c6048b..51a264c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,18 +2,40 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "anyhow" +version = "1.0.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4361135be9122e0870de935d7c439aef945b9f9ddd4199a553b5270b49c82a27" + [[package]] name = "arbitrary" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c38b6b6b79f671c25e1a3e785b7b82d7562ffc9cd3efdc98627e5668a2472490" +dependencies = [ + "derive_arbitrary", +] + +[[package]] +name = "derive_arbitrary" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98e23c06c035dac87bd802d98f368df73a7f2cb05a66ffbd1f377e821fac4af9" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "fuzz-rustc-ast" version = "0.1.0" dependencies = [ + "anyhow", "arbitrary", - "syn", + "quote", + "syn 1.0.88 (git+https://github.com/Nilstrieb/syn?branch=arbitrary)", ] [[package]] @@ -37,7 +59,18 @@ dependencies = [ [[package]] name = "syn" version = "1.0.88" -source = "git+https://github.com/Nilstrieb/syn?branch=arbitrary#a0860e2ae754ade1340683bc54e403540202484b" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebd69e719f31e88618baa1eaa6ee2de5c9a1c004f1e9ecdb58e8352a13f20a01" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "syn" +version = "1.0.88" +source = "git+https://github.com/Nilstrieb/syn?branch=arbitrary#521b62a2934ab332a3a4f248f0dc4ca34648bc9e" dependencies = [ "arbitrary", "proc-macro2", diff --git a/Cargo.toml b/Cargo.toml index 7fd3ae8..8c6ea47 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,9 @@ version = "0.1.0" edition = "2021" [dependencies] +anyhow = "1.0.56" arbitrary = "1.1.0" +quote = "1.0.15" # fork of syn with the arbitrary trait impls syn = { git = "https://github.com/Nilstrieb/syn", branch = "arbitrary", features = ["full", "arbitrary"] } diff --git a/fuzz/.gitignore b/fuzz/.gitignore new file mode 100644 index 0000000..a092511 --- /dev/null +++ b/fuzz/.gitignore @@ -0,0 +1,3 @@ +target +corpus +artifacts diff --git a/fuzz/Cargo.lock b/fuzz/Cargo.lock new file mode 100644 index 0000000..3412d85 --- /dev/null +++ b/fuzz/Cargo.lock @@ -0,0 +1,116 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "anyhow" +version = "1.0.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4361135be9122e0870de935d7c439aef945b9f9ddd4199a553b5270b49c82a27" + +[[package]] +name = "arbitrary" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c38b6b6b79f671c25e1a3e785b7b82d7562ffc9cd3efdc98627e5668a2472490" +dependencies = [ + "derive_arbitrary", +] + +[[package]] +name = "cc" +version = "1.0.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" + +[[package]] +name = "derive_arbitrary" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98e23c06c035dac87bd802d98f368df73a7f2cb05a66ffbd1f377e821fac4af9" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "fuzz-rustc-ast" +version = "0.1.0" +dependencies = [ + "anyhow", + "arbitrary", + "quote", + "syn 1.0.88 (git+https://github.com/Nilstrieb/syn?branch=arbitrary)", +] + +[[package]] +name = "fuzz-rustc-ast-fuzz" +version = "0.0.0" +dependencies = [ + "fuzz-rustc-ast", + "libfuzzer-sys", +] + +[[package]] +name = "libfuzzer-sys" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "336244aaeab6a12df46480dc585802aa743a72d66b11937844c61bbca84c991d" +dependencies = [ + "arbitrary", + "cc", + "once_cell", +] + +[[package]] +name = "once_cell" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9" + +[[package]] +name = "proc-macro2" +version = "1.0.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quote" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "864d3e96a899863136fc6e99f3d7cae289dafe43bf2c5ac19b70df7210c0a145" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "syn" +version = "1.0.88" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebd69e719f31e88618baa1eaa6ee2de5c9a1c004f1e9ecdb58e8352a13f20a01" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "syn" +version = "1.0.88" +source = "git+https://github.com/Nilstrieb/syn?branch=arbitrary#678493490de7c50b79b9461df9a67a22d43e5200" +dependencies = [ + "arbitrary", + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "unicode-xid" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" diff --git a/fuzz/Cargo.toml b/fuzz/Cargo.toml new file mode 100644 index 0000000..8d4c181 --- /dev/null +++ b/fuzz/Cargo.toml @@ -0,0 +1,25 @@ +[package] +name = "fuzz-rustc-ast-fuzz" +version = "0.0.0" +authors = ["Automatically generated"] +publish = false +edition = "2018" + +[package.metadata] +cargo-fuzz = true + +[dependencies] +libfuzzer-sys = "0.4" + +[dependencies.fuzz-rustc-ast] +path = ".." + +# Prevent this from interfering with workspaces +[workspace] +members = ["."] + +[[bin]] +name = "ast" +path = "fuzz_targets/ast.rs" +test = false +doc = false diff --git a/fuzz/fuzz_targets/ast.rs b/fuzz/fuzz_targets/ast.rs new file mode 100644 index 0000000..a900283 --- /dev/null +++ b/fuzz/fuzz_targets/ast.rs @@ -0,0 +1,8 @@ +#![no_main] +use libfuzzer_sys::fuzz_target; + +use fuzz_rustc_ast::RustCode; + +fuzz_target!(|_data: RustCode| { + // fuzzed code goes here +}); diff --git a/run.sh b/run.sh new file mode 100644 index 0000000..5f9ebce --- /dev/null +++ b/run.sh @@ -0,0 +1,78 @@ +#!/bin/bash + +# from the amazing https://github.com/dwrensha/fuzz-rustc + +set -e +set -x + +if [ ! -d rust ]; then + git clone https://github.com/dwrensha/rust.git --branch fuzz +fi + + +rustup override set nightly + +# - enable coverage instrumentation +export RUSTFLAGS="$RUSTFLAGS -C passes=sancov-module -C llvm-args=-sanitizer-coverage-level=4" +export RUSTFLAGS="$RUSTFLAGS -C llvm-args=-sanitizer-coverage-trace-compares" +export RUSTFLAGS="$RUSTFLAGS -C llvm-args=-sanitizer-coverage-inline-8bit-counters" +export RUSTFLAGS="$RUSTFLAGS -C llvm-args=-sanitizer-coverage-pc-table" + +# - enable compilation of rustc_private crates +export RUSTFLAGS="$RUSTFLAGS -Z force-unstable-if-unmarked" + +# - work around https://github.com/rust-fuzz/cargo-fuzz/issues/161 +export RUSTFLAGS="$RUSTFLAGS -C codegen-units=1" + +# - enable debug assertions +export RUSTFLAGS="$RUSTFLAGS -C debug-assertions=on" + +#export RUSTFLAGS="$RUSTFLAGS -Z sanitizer=address" + +# Create seed directory if it does not exist. Add example files here. +mkdir -p seeds + +# Create corpus directory which the fuzzer will fill with interesting inputs. +mkdir -p corpus + +# Create artifact output directory. +mkdir -p artifacts + +# Detect the target. +if [ "$(uname -s)" == "Darwin" ]; then + export TARGET="x86_64-apple-darwin" +elif [ "$(uname -s)" == "Linux" ]; then + export TARGET="x86_64-unknown-linux-gnu" +else + echo "Sorry, currently only Mac OS and Linux are supported" + exit 1 +fi + +# This variable tells the new rustc (i.e. the one we're compiling) what version it +# should consider itself to have. This is used when loading precompiled libstd and other +# crates. If the rustc version recorded in those crates' metadata does not match this, +# then the compiler quits early. +export CFG_VERSION=`rustc --version | cut -f2- -d ' '` + +# Usually we can use the precompiled libstd from rustup. +TOOLCHAIN_ROOT=${RUSTUP_BASE:-$HOME/.rustup}/toolchains/nightly-$TARGET + +# If a metadata change has landed on master and is not yet in a nightly release, +# we may need to compile our own libstd. `./x.py build --stage 1` should suffice. +# If fuzzing immediately fails on an empty input, this is a good thing to try. +# (Note that you will also need to change CFG_VERSION, above.) +#TOOLCHAIN_ROOT=$HOME/src/rust/build/x86_64-unknown-linux-gnu/stage1/ + +# Custom environment variable indicating where to look for the precompiled libstd. +export FUZZ_RUSTC_LIBRARY_DIR=$TOOLCHAIN_ROOT/lib/rustlib/$TARGET/lib + +# Set some environment variables that are needed when building the rustc source code. +export CFG_COMPILER_HOST_TRIPLE=$TARGET +export CFG_RELEASE_CHANNEL=nightly +export CFG_RELEASE=unknown +export REAL_LIBRARY_PATH_VAR=foobar + +# Any writable location will do for this one. +export RUSTC_ERROR_METADATA_DST=/tmp/rustc_error_metadata + +export RUSTC_INSTALL_BINDIR=/tmp/rustc_install_bindir \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..236ce73 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,18 @@ +use arbitrary::{Arbitrary, Unstructured}; + +#[derive(Debug)] +pub struct RustCode(pub String); + +impl<'a> Arbitrary<'a> for RustCode { + fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result { + let ast = syn::Item::arbitrary(u)?; + + let tokens = quote::quote! { #ast }; + + Ok(RustCode(tokens.to_string())) + } + + fn size_hint(_depth: usize) -> (usize, Option) { + (5, Some(10)) + } +} diff --git a/src/main.rs b/src/main.rs index 04a95d0..ce98322 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,11 +1,24 @@ +use anyhow::Context; use arbitrary::Arbitrary; use std::path::PathBuf; -fn main() { - let data = std::fs::read(PathBuf::from(file!()).parent().unwrap().join("Cargo.toml")).unwrap(); +fn main() -> anyhow::Result<()> { + let path = PathBuf::from(file!()) + .parent() + .unwrap() + .parent() + .unwrap() + .join("Cargo.toml"); + let data = std::fs::read(&path).context(path.display().to_string())?; + + // %%% G% GGGG � let mut unstructured = arbitrary::Unstructured::new(&data); - let ast = syn::Item::arbitrary(&mut unstructured); + let ast = syn::Item::arbitrary_take_rest(unstructured).context("from arbitrary")?; - println!("{ast}"); + let tokens = quote::quote! { #ast }; + + println!("{tokens}"); + + Ok(()) }