From e91f8b5db2dbfc8c1e4f835990b9d1f08a661430 Mon Sep 17 00:00:00 2001 From: Jesse Ruderman Date: Fri, 8 Jul 2011 02:16:46 -0700 Subject: [PATCH] Pieces of a fuzzer, WIP --- src/fuzzer/ast_match.rs | 38 ++++++++++++++++ src/fuzzer/fuzzer.rs | 84 ++++++++++++++++++----------------- src/fuzzer/ivec_fuzz.rs | 98 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 180 insertions(+), 40 deletions(-) create mode 100644 src/fuzzer/ast_match.rs create mode 100644 src/fuzzer/ivec_fuzz.rs diff --git a/src/fuzzer/ast_match.rs b/src/fuzzer/ast_match.rs new file mode 100644 index 00000000000..e3196c33e21 --- /dev/null +++ b/src/fuzzer/ast_match.rs @@ -0,0 +1,38 @@ +use std; +import std::ivec; + +fn ivec_equal[T](&T[] v, &T[] u, fn (&T, &T) -> bool element_equality_test) -> bool { + auto Lv = ivec::len(v); + if (Lv != ivec::len(u)) { + ret false; + } + auto i = 0u; + while (i < Lv) { + if (!element_equality_test(v.(i), u.(i))) { + ret false; + } + i += 1u; + } + ret true; +} + +fn builtin_equal[T](&T a, &T b) -> bool { + ret a == b; +} + +fn main() { + // These pass + assert builtin_equal(5, 5); + assert !builtin_equal(5, 4); + + // This passes + assert !ivec_equal(~[5, 5], ~[5], builtin_equal); + + // These crash + // https://github.com/graydon/rust/issues/633 + assert !ivec_equal(~[5, 5], ~[5, 4], builtin_equal); + assert !ivec_equal(~[5, 5], ~[4, 5], builtin_equal); + assert ivec_equal(~[5, 5], ~[5, 5], builtin_equal); + + log_err "Pass"; +} diff --git a/src/fuzzer/fuzzer.rs b/src/fuzzer/fuzzer.rs index 2de291eac5b..f7bc514a700 100644 --- a/src/fuzzer/fuzzer.rs +++ b/src/fuzzer/fuzzer.rs @@ -1,3 +1,6 @@ +use std; +use rustc; + import std::fs; import std::getopts; import std::getopts::optopt; @@ -5,56 +8,57 @@ import std::getopts::opt_str; import std::io; import std::vec; +import std::ivec; +import std::str; -type src_gen = iter() -> str; - -iter dir_src_gen(str dir) -> str { -} - -fn usage(str binary) { - io::stdout().write_line("usage"); -} +import rustc::back::link; +import rustc::syntax::ast; +import driver = rustc::driver::rustc; // see https://github.com/graydon/rust/issues/624 +import rustc::driver::session; -type session = rec(str srcdir); -fn make_session(vec[str] args) -> session { - // Directory of rust source files to use as input - auto opt_src = "src"; - - auto binary = vec::shift[str](args); - auto opts = [optopt(opt_src)]; - auto match; - alt (getopts::getopts(args, opts)) { - case (getopts::failure(?f)) { - log_err #fmt("error: %s", getopts::fail_str(f)); - fail; +fn find_rust_files(&mutable str[] files, str root) { + for (str filename in fs::list_dir(root)) { + if (str::ends_with(filename, ".rs")) { + files += ~[filename]; } - case (getopts::success(?m)) { - match = m; - } - }; - - if (!opt_present(match, opt_src)) { - usage(binary); - fail; } +} - auto srcdir = opt_str(match, opt_src); +fn main(vec[str] args) { + auto files = ~[]; + auto root = "/Users/jruderman/code/rust/src/lib/"; // XXX + find_rust_files(files, root); // not using driver::time here because that currently screws with passing-a-mutable-array - ret rec(srcdir = srcdir); -} + auto binary = vec::shift[str](args); + auto binary_dir = fs::dirname(binary); -fn log_session(session sess) { - log #fmt("srcdir: %s", sess.srcdir); -} + let @session::options sopts = + @rec(library=false, + static=false, + optimize=0u, + debuginfo=false, + verify=true, + run_typestate=true, + save_temps=false, + stats=false, + time_passes=false, + time_llvm_passes=false, + output_type=link::output_type_bitcode, + library_search_paths=[binary_dir + "/lib"], + sysroot=driver::get_default_sysroot(binary), + cfg=~[], + test=false); -fn run_session(session sess) { -} + let session::session sess = driver::build_session(sopts); -fn main(vec[str] args) { - auto sess = make_session(args); - log_session(sess); - run_session(sess); + log_err ivec::len(files); + for (str file in files) { + log_err file; + // Can't use parse_input here because of https://github.com/graydon/rust/issues/632 :( + //auto crate = driver::parse_input(sess, ~[], file); + //let @ast::crate crate = driver::time(true, "parsing " + file, bind driver::parse_input(sess, ~[], file)); + } } // Local Variables: diff --git a/src/fuzzer/ivec_fuzz.rs b/src/fuzzer/ivec_fuzz.rs new file mode 100644 index 00000000000..af9bb7f4d64 --- /dev/null +++ b/src/fuzzer/ivec_fuzz.rs @@ -0,0 +1,98 @@ +/* + +Idea: provide functions for 'exhaustive' and 'random' modification of vecs. + + two functions, "return all edits" and "return a random edit" <-- leaning toward this model + or + two functions, "return the number of possible edits" and "return edit #n" + +It would be nice if this could be data-driven, so the two functions could share information: + type vec_modifier = rec(fn (&int[] v, uint i) -> int[] fun, uint lo, uint di); + const vec_modifier[] vec_modifiers = ~[rec(fun=vec_omit, 0u, 1u), ...]; +But that gives me "error: internal compiler error unimplemented consts that's not a plain literal". +https://github.com/graydon/rust/issues/570 + +vec_edits is not an iter because iters might go away and: +https://github.com/graydon/rust/issues/639 + +vec_omit and friends are not type-parameterized because: +https://github.com/graydon/rust/issues/640 + +*/ + +use std; +import std::ivec; +import std::ivec::slice; +import std::ivec::len; +import std::int; + +//fn vec_reverse(&int[] v) -> int[] { ... } + +fn vec_omit (&int[] v, uint i) -> int[] { slice(v, 0u, i) + slice(v, i+1u, len(v)) } +fn vec_dup (&int[] v, uint i) -> int[] { slice(v, 0u, i) + ~[v.(i)] + slice(v, i, len(v)) } +fn vec_swadj (&int[] v, uint i) -> int[] { slice(v, 0u, i) + ~[v.(i+1u), v.(i)] + slice(v, i+2u, len(v)) } +fn vec_prefix (&int[] v, uint i) -> int[] { slice(v, 0u, i) } +fn vec_suffix (&int[] v, uint i) -> int[] { slice(v, i, len(v)) } + +fn vec_poke (&int[] v, uint i, int x) -> int[] { slice(v, 0u, i) + ~[x] + slice(v, i+1u, len(v)) } +fn vec_insert (&int[] v, uint i, int x) -> int[] { slice(v, 0u, i) + ~[x] + slice(v, i, len(v)) } + +// Iterates over 0...length, skipping the specified number on each side. +iter ix(uint skip_low, uint skip_high, uint length) -> uint { let uint i = skip_low; while (i + skip_high <= length) { put i; i += 1u; } } + +// Returns a bunch of modified versions of v, some of which introduce new elements (borrowed from xs). +fn vec_edits(&int[] v, &int[] xs) -> int[][] { + let int[][] edits = ~[]; + let uint Lv = len(v); + + if (Lv != 1u) { edits += ~[~[]]; } // When Lv == 1u, this is redundant with omit + //if (Lv >= 3u) { edits += ~[vec_reverse(v)]; } + + for each (uint i in ix(0u, 1u, Lv)) { edits += ~[vec_omit (v, i)]; } + for each (uint i in ix(0u, 1u, Lv)) { edits += ~[vec_dup (v, i)]; } + for each (uint i in ix(0u, 2u, Lv)) { edits += ~[vec_swadj (v, i)]; } + for each (uint i in ix(1u, 2u, Lv)) { edits += ~[vec_prefix(v, i)]; } + for each (uint i in ix(2u, 1u, Lv)) { edits += ~[vec_suffix(v, i)]; } + + for each (uint j in ix(0u, 1u, len(xs))) { + for each (uint i in ix(0u, 1u, Lv)) { edits += ~[vec_poke (v, i, xs.(j))]; } + for each (uint i in ix(0u, 0u, Lv)) { edits += ~[vec_insert(v, i, xs.(j))]; } + } + + edits +} + +// Would be nice if this were built in: https://github.com/graydon/rust/issues/424 +fn vec_to_str(&int[] v) -> str { + auto i = 0u; + auto s = "["; + while (i < len(v)) { + s += int::str(v.(i)); + if (i + 1u < len(v)) { + s += ", " + } + i += 1u; + } + ret s + "]"; +} + +fn show_edits(&int[] a, &int[] xs) { + log_err "=== Edits of " + vec_to_str(a) + " ==="; + auto b = vec_edits(a, xs); + for each (uint i in ix(0u, 1u, len(b))) { + log_err vec_to_str(b.(i)); + } +} + +fn demo_edits() { + auto xs = ~[7, 8]; + show_edits(~[], xs); + show_edits(~[1], xs); + show_edits(~[1,2], xs); + show_edits(~[1,2,3], xs); + show_edits(~[1,2,3,4], xs); +} + +fn main() { + demo_edits(); +} -- 2.44.0