Skip to content

Commit

Permalink
[tmp] rudimentary support for rustc fuzzing
Browse files Browse the repository at this point in the history
If you happen to stumble across this, here's how to build rustc with AFL
instrumentation and make it work with this commit:

1. Run 'cargo install afl'. This will compile AFL and the LLVM plugins
   needed to build rust with AFL instrumentation.

2. Clone <https://github.com/rust-lang/rust>.

3. Set LIBRARY_PATH="$(realpath ~/.local/share/afl.rs/rustc-*/afl.rs-*/afl-llvm-rt"

4. Set RUSTFLAGS="-C llvm-args=-sanitizer-coverage-level=3 \
    -C llvm-args=-sanitizer-coverage-trace-pc-guard \
    -C passes=sancov \
    -l afl-llvm-rt \
    -L $(realpath ~/.local/share/afl.rs/rustc-*/afl.rs-*/afl-llvm-rt)"

5. Build rustc:
    ./x.py build

6. Test that it works:
    cargo afl showmap -o trace.txt -m 1024 -- build/x86_64-unknown-linux-gnu/stage2/bin/rustc --emit asm input.rs
    cat trace.txt

7. Clone <https://github.com/rust-fuzz/afl.rs>. This will give you the AFL
   version that you need to build this fuzzer against (edit make.sh here to
   point to afl.rs/afl-*/).

8. Edit main.cc to point /home/vegard/... paths to your own rustc/etc.

9. Run: mkdir output/ stderr/

10. Run: bash make.sh && ./main
  • Loading branch information
vegard committed May 10, 2018
1 parent 411bbb8 commit c80b1a7
Show file tree
Hide file tree
Showing 3 changed files with 266 additions and 25 deletions.
50 changes: 27 additions & 23 deletions main.cc
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ struct testcase {
//
// Too large test cases slow everything down, but new mutations
// tend to make them bigger.
const unsigned int max_size = 2048;
const unsigned int max_size = 1800;
unsigned int size = root->size();
score += ((size < max_size) ? max_size : size - max_size) / 5;
#endif
Expand Down Expand Up @@ -279,12 +279,15 @@ int main(int argc, char *argv[])
error(EXIT_FAILURE, errno, "gettimeofday()");

static char stderr_filename[PATH_MAX];
snprintf(stderr_filename, sizeof(stderr_filename), "stderr-%lu.txt", tv_start.tv_sec);
snprintf(stderr_filename, sizeof(stderr_filename), "stderr/%lu-%d.txt", tv_start.tv_sec, getpid());

static char filename[PATH_MAX];
snprintf(filename, sizeof(filename), "output/%lu-%d.rs", tv_start.tv_sec, getpid());

unsigned int mutation_counters[nr_mutations] = {};
unsigned int trace_bits_counters[MAP_SIZE] = {};

fixed_priority_queue<testcase> pq(1200);
fixed_priority_queue<testcase> pq(750);

unsigned int nr_execs = 0;
unsigned int nr_execs_without_new_bits = 0;
Expand All @@ -298,8 +301,8 @@ int main(int argc, char *argv[])
#endif

#if 1 // periodically resetting (restarting) everything seems beneficial for now; interesting future angle WRT SAT solver restarts
if (nr_execs_without_new_bits == 50) {
pq = fixed_priority_queue<testcase>(1200);
if (nr_execs_without_new_bits == 250) {
pq = fixed_priority_queue<testcase>(750);
for (unsigned int i = 0; i < nr_mutations; ++i)
mutation_counters[i] = 0;
for (unsigned int i = 0; i < MAP_SIZE; ++i)
Expand Down Expand Up @@ -362,12 +365,7 @@ int main(int argc, char *argv[])
//
// exec() the compiler. You need to substitute the path to your own compiler here.

//if (execlp("/usr/bin/g++-5", "g++", "-x", "c++", "-std=c++14", "-Os", "-c", "-", NULL) == -1)
//if (execlp("/home/vegard/personal/programming/gcc/build/gcc/xgcc", "xgcc", "-x", "c++", "-std=c++14", "-O3", "-c", "-", NULL) == -1)
//if (execlp("/home/vegard/personal/programming/gcc/build/gcc/xgcc", "xgcc", "-x", "c++", "-std=c++14", "-O3", "-Wall", "-fpermissive", "-g", "-pg", "-fwhole-program", "-ftree-pre", "-fstack-protector-all", "-fsanitize=undefined", "-fsanitize=address", "-fsanitize=leak", "-c", "-", NULL) == -1)
//if (execlp("/home/vegard/personal/programming/gcc/build/gcc/xgcc", "xgcc", "-x", "c++", "-std=c++14", "-O3", "-Wall", "-fpermissive", "-g", "-pg", "-fwhole-program", "-ftree-pre", "-fstack-protector-all", "-fsanitize=undefined", "-fsanitize=address", "-fsanitize=leak", "-S", "-", NULL) == -1)
// invoke cc1plus directly (skips fork+exec)
if (execlp("/home/vegard/personal/programming/gcc/build/gcc/cc1plus", "cc1plus", "-quiet", "-imultiarch", "x86_64-linux-gnu", "-iprefix", "/home/vegard/personal/programming/gcc/build/gcc/../lib/gcc/x86_64-pc-linux-gnu/8.0.1/", "-D_GNU_SOURCE", "-", "-quiet", "-dumpbase", "-", "-mtune=generic", "-march=x86-64", "-auxbase", "-", "-g", "-O3", "-Wall", "-std=c++14", "-p", "-fpermissive", "-fwhole-program", "-ftree-pre", "-fstack-protector-all", /*"-fsanitize=undefined",*/ "-fsanitize=address", "-fsanitize=leak", "-faggressive-loop-optimizations", "-fauto-inc-dec", "-fbranch-probabilities", "-fbranch-target-load-optimize2", "-fcheck-data-deps", "-fcompare-elim", "-fdce", "-fdse", "-fexpensive-optimizations", "-fhoist-adjacent-loads", "-fgcse-lm", "-fgcse-sm", "-fipa-profile", "-fno-toplevel-reorder", "-fsched-group-heuristic", "-fschedule-fusion", "-fschedule-insns", "-fschedule-insns2", "-ftracer", "-funroll-loops", "-fvect-cost-model", "-o", "-.s", NULL) == -1)
if (execlp("/home/vegard/rust/build/x86_64-unknown-linux-gnu/stage2/bin/rustc", "/home/vegard/rust/build/x86_64-unknown-linux-gnu/stage2/bin/rustc", "--emit", "asm", "-Z", "unstable-options", "--error-format", "short", /*"-Z", "no-trans",*/ "-Z", "no-verify", "-Z", "fewer-names", "-Z", "query-threads=1", "-", NULL) == -1)
error(EXIT_FAILURE, errno, "execvp()");
}

Expand Down Expand Up @@ -397,12 +395,13 @@ int main(int argc, char *argv[])
++nr_execs;

if (WIFSIGNALED(status)) {
#if 0 // Ignore segfaults for now, have to wait for a fix for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=84576
#if 1 // Ignore segfaults for now, have to wait for a fix for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=84576
printf("signal %d:\n", WTERMSIG(status));
root->print(stdout);
printf("\n");

FILE *fp = fopen("/tmp/random.cc", "w");
printf("Writing reproducer to %s\n", filename);
FILE *fp = fopen(filename, "w");
if (!fp)
error(EXIT_FAILURE, errno, "fopen()");
root->print(fp);
Expand All @@ -418,24 +417,23 @@ int main(int argc, char *argv[])
if (!f)
error(EXIT_FAILURE, errno, "fopen()");

static char buffer[10 * 4096];
static char buffer[100 * 4096];
size_t len = fread(buffer, 1, sizeof(buffer), f);
fclose(f);

if (len > 0) {
buffer[len - 1] = '\0';

//fwrite(buffer, 1, len, stdout);

// Check for ICEs, but ignore a set of specific ones which we've
// already reported and which keep showing up.
if (strstr(buffer, "internal compiler error") && !strstr(buffer, "types may not be defined in parameter types") && !strstr(buffer, "internal compiler error: in synthesize_implicit_template_parm") && !strstr(buffer, "internal compiler error: in search_anon_aggr") && !strstr(buffer, "non_type_check") && !strstr(buffer, "internal compiler error: in xref_basetypes, at") && !strstr(buffer, "internal compiler error: in build_capture_proxy") && !strstr(buffer, "internal compiler error: tree check: expected record_type or union_type or qual_union_type, have array_type in reduced_constant_expression_p") && !strstr(buffer, "internal compiler error: in cp_lexer_new_from_tokens") && !strstr(buffer, "internal compiler error: in extract_constrain_insn") && !strstr(buffer, "in lra_eliminate_reg_if_possible") && !strstr(buffer, "Max. number of generated reload insns per insn is achieved") && !strstr(buffer, "standard_conversion") && !strstr(buffer, "in pop_local_binding") && !strstr(buffer, "of kind implicit_conv_expr") && !strstr(buffer, "in cp_build_addr_expr_1") && !strstr(buffer, "in poplevel_class, at") && !strstr(buffer, "force_constant_size")) {
if ((strstr(buffer, "fatal error") || strstr(buffer, "egmentation") || strstr(buffer, "segfault") || strstr(buffer, "signal 6:") || strstr(buffer, "Assertion ") || strstr(buffer, "Aborted") || strstr(buffer, "internal compiler error")) && !strstr(buffer, "invalid loop id for break: not inside loop scope") && !strstr(buffer, "local_def_id: no entry for") && !strstr(buffer, "tuple struct pattern not applied to an ADT") && !strstr(buffer, "assertion failed: self.tcx.sess.err_count() > 0") && !strstr(buffer, "unexpected type for tuple pattern: TyError") && !strstr(buffer, "invalid loop id for break: label not found") && !strstr(buffer, "invalid loop id for continue: not inside loop scope")) {
printf("ICE:\n");
root->print(stdout);
printf("\n");

char filename[PATH_MAX];
snprintf(filename, sizeof(filename), "output/%lu.cc", tv.tv_sec);
printf("Writing reproducer to %s\n", filename);

FILE *fp = fopen(filename, "w");
if (!fp)
error(EXIT_FAILURE, errno, "fopen()");
Expand All @@ -460,11 +458,6 @@ int main(int argc, char *argv[])
}
}

if (new_bits)
nr_execs_without_new_bits = 0;
else
++nr_execs_without_new_bits;

auto mutations = current.mutations;
mutations.insert(mutation);
testcase new_testcase(root, current.generation + 1, mutations, current.mutation_counter + ++mutation_counters[mutation], current.new_bits + new_bits);
Expand All @@ -474,6 +467,17 @@ int main(int argc, char *argv[])
printf("\n");

pq.push(new_testcase);

if (new_bits)
nr_execs_without_new_bits = 0;
else
++nr_execs_without_new_bits;
} else {
++nr_execs_without_new_bits;
}

if (nr_execs_without_new_bits > 150) {
pq.pop();
}

remove_shm();
Expand Down
4 changes: 2 additions & 2 deletions make.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ set -e
set -x

# TODO: make configurable
AFL_PATH="$PWD/afl-2.52b"
AFL_PATH="/home/vegard/afl.rs/afl-2.52b/"

python rules2code.py < rules/cxx.txt > rules/cxx.hh
python rules2code.py < rules/rust.txt > rules/cxx.hh
g++ -std=c++11 -I"${AFL_PATH}" -Wall -g -o main main.cc

mkdir -p output
237 changes: 237 additions & 0 deletions rules/rust.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,237 @@
"[] fn [x][]([]) -> [][u32] { []; []; []; []; [0] } [] fn main() { []; []; []; []; [] }"
"[] fn [x][]([]) -> [] [{}]"
"[]; []"
"[] { [] } []"
"[] ([]) []"
"[x]x"
"[1]0"
"0"
"1"
"false"
"true"
"'x'"
"\[[]\]"
"[1], [2]"
"[1]; [2]"
"[1] + [2]"
"let x"
"let [x] = [5]"
"let [x]x = [x]"
"let ([x], [y]) = ([1], [2])"
"let [x]: [i32] = [5]"
"[x] = [10]"
"let [mut] [x] = [5]"
"i32"
"[x]: [i32]"
"\"foo\""
"println!(\"!\")"
"println!(\"{}\", [x]);"
"return [x]"
"!"
"[x].[len]()"
"x\[[0]\]"
"[0]..[1]"
"[0],"
"[x].[0]"
"[i32] { [x] }"
"if [x] [==] [5] { [] } else { [] }"
"loop { [] }"
"while [true] { [] }"
"[x] % [5] [==] [0]"
"for ([x] = [0]; [x] [<] [10]; [x++]) { [] }"
"for [x] in [0]..[10] { [] }"
"[x].enumerate()"
"break"
"continue"
"'[L]: []"
"break '[L]"
"continue '[L]"
"[] []"
"#[]\[allow(unused_variables)\]"
"#[]\[allow(unreachable_code)\]"
"#[]\[allow(dead_code)\]"
"!"
"let [x] = vec!\[[]\];"
"match [x].get([7]) { [] }"
"Some([x]) => [0]"
"None => [0]"
"mut [x]"
"&[] [mut] [x]"
""
"bool"
"Vec<[i32]>"
"|[x]| [x]"
"*x"
"&x"
"[x].[as_str]([])"
"'[a]"
"<[]>"
"<'[a]>"
"&'a [u32]"
"str"
"'[a]"
"impl"
"impl<'[a]> [Foo]<'[a]> { [] }"
"[Foo] { [] }"
"[x]: [x]"
"[x].[x]([])"
"static"
"[] use [std]::[cell]::[Cell]"
"[] struct [Foo] [] { [] }"
"assert_eq!([1], [1])"
"#\[derive(Debug)\]"
"[] struct [Foo]([])"
"[] enum [Foo] [] { [] }"
"[x]::[x]"
"String"
"[_] => [0],"
"['a'] ... ['z']"
"[x] @ [0] => 0,"
"[x] | [0] => 0,"
"const"
"Vec::new()"
"Vec::<[bool]>::new()"
"[x] * [x]"
"f64"
"3.14159216"
"assert!([1])"
"b\"whatever\""
"#\[derive([Debug])\]"
"impl [Drop] for [Foo] { [] }"
"Debug"
"Drop"
"Foo"
"*[mut] ([])"
"fn[](*[mut] ([]))"
"unsafe []"
"unsafe { [] }"
"Clone"
"&[x] as &[Clone]"
"|[x]| { [] }"
"|[x]: [i32]| { [] }"
"move |[x]: [i32]| { [] }"
"move"
"<[Foo] as [Foo]>"
"\[[u8]; [10]\]"
"[] pub"
"macro_rules! [vec] { ( $( $[x]:[expr] ),* ) => { [] } }"
"macro_rules! [x] { [] }"
"$( [] )*"
"$[x]"
"{{ [] }}"
"item"
"block"
"stmt"
"pat"
"expr"
"ty"
"ident"
"path"
"tt"
"meta"
"None?"
"Some([x])?"
"Some([x])"
"![true]"
"-[x]"
"[] mod [math] [{}]"
"#\[path = [\"x\"]\]"
"#!\[crate_name = [\"x\"]\]"
"#!\[crate_type = [\"lib\"]\] []"
"extern crate [std]"
"extern crate [std] as [std]"
"#\[link([name] = [\"x\"])"
"#\[cfg([test])\]"
"#\[[test]\]"
"#\[cfg(target_os=[\"linux\"])\]"
"#\[[crate_name]=[\"x\"]\]"
"#\[[plugin]([x])\]"
"crate_type"
"feature"
"no_builtins"
"no_main"
"no_start"
"no_std"
"plugin"
"recursion_limit"
"main"
"plugin_registrar"
"start"
"should_panic"
"cold"
"thread_local"
"link_args"
"link"
"linked_from"
"link_name"
"linkage"
"repr"
"macro_use"
"macro_reexport"
"macro_export"
"no_link"
"export_name"
"link_section"
"no_mangle"
"simd"
"unsafe_destructor_blind_to_params"
"unsafe_no_drop_flag"
"doc"
"rustc_on_unimplemented"
"debug_assertions"
"target_arch"
"target_endian"
"target_env"
"target_family"
"target_os"
"target_pointer_width"
"target_vendor"
"unix"
"windows"
"allow"
"deny"
"forbid"
"warn"
"lang"
"inline"
"inline(always)"
"inline(never)"
"derive([PartialEq], [Clone])"
"feature"
"advanced_slice_patterns"
"slice_patterns"
"asm"
"asm!"
"asm!([\"nop\"])"
"asm!(\"xor %eax, %eax\" : [] : [] : [\"eax\"])"
"asm!(\"in %dx, %al\" : \"={[al]}\"([x]) : \"{[dx]}\"([x]))"
"[panic]!([])"
"panic"
"file"
"line"
"debug_assert"
"array"
"bool"
"char"
"f32"
"f64"
"fn"
"i8"
"i16"
"i32"
"i64"
"isize"
"pointer"
"reference"
"slice"
"str"
"tuple"
"u8"
"u16"
"u32"
"u64"
"unit"
"usize"
"i128"
"u128"
"never"

0 comments on commit c80b1a7

Please sign in to comment.