Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fuzzing4 #780

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 65 additions & 6 deletions src/fuzzer/fuzzer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,9 @@ fn safe_to_steal(e: ast::expr_) -> bool {
ast::expr_ret(option::none.) { false }
ast::expr_put(option::none.) { false }

ast::expr_ret(_) { false /* lots of code generation issues, such as https://github.com/graydon/rust/issues/770 */ }
ast::expr_fail(_) { false }

_ {
true
}
Expand Down Expand Up @@ -149,7 +152,7 @@ fn as_str(f: fn(ioivec::writer) ) -> str {
ret w.get_str();
}

fn pp_variants(crate: &ast::crate, codemap: &codemap::codemap, filename: &str) {
fn check_variants_of_ast(crate: &ast::crate, codemap: &codemap::codemap, filename: &str) {
let exprs = steal_exprs(crate);
let exprsL = ivec::len(exprs);
if (exprsL < 100u) {
Expand All @@ -166,11 +169,64 @@ fn pp_variants(crate: &ast::crate, codemap: &codemap::codemap, filename: &str) {
// 1u would be sane here, but the pretty-printer currently has lots of whitespace and paren issues,
// and https://github.com/graydon/rust/issues/766 is hilarious.
check_roundtrip_convergence(str3, 7u);
//check_whole_compiler(str3);
}
}
}
}

// We'd find more bugs if we could take an AST here, but
// - that would find many "false positives" or unimportant bugs
// - that would be tricky, requiring use of tasks or serialization or randomness.
// This seems to find plenty of bugs as it is :)
fn check_whole_compiler(code: &str) {
let filename = "test.rs";
write_file(filename, code);
let p = std::run::program_output("/Users/jruderman/code/rust/build/stage1/rustc", ["-c", filename]);
//log_err #fmt("Status: %d", p.status);
//log_err "Output: " + p.out;
if p.err != "" {
if contains(p.err, "argument of incompatible type") {
log_err "https://github.com/graydon/rust/issues/769";
} else if contains(p.err, "Cannot create binary operator with two operands of differing type") {
log_err "https://github.com/graydon/rust/issues/770";
} else if contains(p.err, "May only branch on boolean predicates!") {
log_err "https://github.com/graydon/rust/issues/770 or https://github.com/graydon/rust/issues/776";
} else if contains(p.err, "Invalid constantexpr cast!") && contains(code, "!") {
log_err "https://github.com/graydon/rust/issues/777";
} else if contains(p.err, "Both operands to ICmp instruction are not of the same type!") && contains(code, "!") {
log_err "https://github.com/graydon/rust/issues/777 #issuecomment-1678487";
} else if contains(p.err, "Ptr must be a pointer to Val type!") && contains(code, "!") {
log_err "https://github.com/graydon/rust/issues/779";
} else if contains(p.err, "Calling a function with bad signature!") && (contains(code, "iter") || contains(code, "range")) {
log_err "https://github.com/graydon/rust/issues/771 - calling an iter fails";
} else if contains(p.err, "Calling a function with a bad signature!") && contains(code, "empty") {
log_err "https://github.com/graydon/rust/issues/775 - possibly a modification of run-pass/import-glob-crate.rs";
} else if contains(p.err, "Invalid type for pointer element!") && contains(code, "put") {
log_err "https://github.com/graydon/rust/issues/773 - put put ()";
} else if contains(p.err, "pointer being freed was not allocated") && contains(p.out, "Out of stack space, sorry") {
log_err "https://github.com/graydon/rust/issues/768 + https://github.com/graydon/rust/issues/778"
} else {
log_err "Stderr: " + p.err;
fail "Unfamiliar error message";
}
} else if contains(p.out, "non-exhaustive match failure") && contains(p.out, "alias.rs") {
log_err "https://github.com/graydon/rust/issues/772";
} else if contains(p.out, "non-exhaustive match failure") && contains(p.out, "trans.rs") && contains(code, "put") {
log_err "https://github.com/graydon/rust/issues/774";
} else if contains(p.out, "Out of stack space, sorry") {
log_err "Possibly a variant of https://github.com/graydon/rust/issues/768";
} else if p.status == 256 {
if !contains(p.out, "error:") {
fail "Exited with status 256 without a span-error";
}
} else if p.status == 11 {
log_err "What is this I don't even";
} else if p.status != 0 {
fail "Unfamiliar status code";
}
}

fn parse_and_print(code: &str) -> str {
let filename = "tmp.rs";
let codemap = codemap::new_codemap();
Expand All @@ -186,7 +242,9 @@ fn content_is_dangerous_to_modify(code: &str) -> bool {
let dangerous_patterns = [
"obj", // not safe to steal; https://github.com/graydon/rust/issues/761
"#macro", // not safe to steal things inside of it, because they have a special syntax
" be " // don't want to replace its child with a non-call: "Non-call expression in tail call"
"#", // strange representation of the arguments to #fmt, for example
" be ", // don't want to replace its child with a non-call: "Non-call expression in tail call"
"@" // hangs when compiling: https://github.com/graydon/rust/issues/768
];

for p: str in dangerous_patterns { if contains(code, p) { ret true; } }
Expand Down Expand Up @@ -277,18 +335,18 @@ fn check_convergence(files: &str[]) {
}
}

fn check_convergence_of_variants(files: &str[]) {
fn check_variants(files: &str[]) {
for file in files {
if !file_is_confusing(file) {
let s = read_whole_file(file);
if content_is_dangerous_to_modify(s) || content_is_confusing(s) { cont; }
log_err "check_convergence_of_variants: " + file;
log_err "check_variants: " + file;
let codemap = codemap::new_codemap();
let crate = parser::parse_crate_from_source_str(file, s, ~[], codemap);
log_err as_str(bind pprust::print_crate(codemap, crate, file,
ioivec::string_reader(s), _,
pprust::no_ann()));
pp_variants(*crate, codemap, file);
check_variants_of_ast(*crate, codemap, file);
}
}
}
Expand All @@ -303,7 +361,8 @@ fn main(args: vec[str]) {

find_rust_files(files, root);
check_convergence(files);
check_convergence_of_variants(files);
check_variants(files);
log_err "Fuzzer done";
}

// Local Variables:
Expand Down
37 changes: 28 additions & 9 deletions src/lib/run_program.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,21 +38,26 @@ type program =
fn get_id() -> int ;
fn input() -> io::writer ;
fn output() -> io::reader ;
fn err() -> io::reader ;
fn close_input() ;
fn finish() -> int ;
};

fn start_program(prog: str, args: vec[str]) -> @program {
let pipe_input = os::pipe();
let pipe_output = os::pipe();
let pid = spawn_process(prog, args, pipe_input.in, pipe_output.out, 0);
let pipe_err = os::pipe();
let pid = spawn_process(prog, args, pipe_input.in, pipe_output.out,
pipe_err.out);

if pid == -1 { fail; }
os::libc::close(pipe_input.in);
os::libc::close(pipe_output.out);
os::libc::close(pipe_err.out);
obj new_program(pid: int,
mutable in_fd: int,
out_file: os::libc::FILE,
err_file: os::libc::FILE,
mutable finished: bool) {
fn get_id() -> int { ret pid; }
fn input() -> io::writer {
Expand All @@ -61,6 +66,9 @@ fn start_program(prog: str, args: vec[str]) -> @program {
fn output() -> io::reader {
ret io::new_reader(io::FILE_buf_reader(out_file, false));
}
fn err() -> io::reader {
ret io::new_reader(io::FILE_buf_reader(err_file, false));
}
fn close_input() {
let invalid_fd = -1;
if in_fd != invalid_fd {
Expand All @@ -78,21 +86,32 @@ fn start_program(prog: str, args: vec[str]) -> @program {
self.close_input();
if !finished { os::waitpid(pid); }
os::libc::fclose(out_file);
os::libc::fclose(err_file);
}
}
ret @new_program(pid, pipe_input.out, os::fd_FILE(pipe_output.in), false);
ret @new_program(pid,
pipe_input.out,
os::fd_FILE(pipe_output.in),
os::fd_FILE(pipe_err.in),
false);
}

fn program_output(prog: str, args: vec[str]) -> {status: int, out: str} {
let pr = start_program(prog, args);
pr.close_input();
let out = pr.output();
fn read_all(rd: &io::reader) -> str {
let buf = "";
while !out.eof() {
let bytes = out.read_bytes(4096u);
while !rd.eof() {
let bytes = rd.read_bytes(4096u);
buf += str::unsafe_from_bytes(bytes);
}
ret {status: pr.finish(), out: buf};
ret buf;
}

fn program_output(prog: str, args: vec[str])
-> {status: int, out: str, err: str} {
let pr = start_program(prog, args);
pr.close_input();
ret {status: pr.finish(),
out: read_all(pr.output()),
err: read_all(pr.err())};
}
// Local Variables:
// mode: rust
Expand Down