diff options
author | Jack Lloyd <[email protected]> | 2017-08-24 10:31:14 -0400 |
---|---|---|
committer | Jack Lloyd <[email protected]> | 2017-08-25 17:36:51 -0400 |
commit | 8ac2697a3b9e6242e2f6d0c5e1d83fc150fd6ff0 (patch) | |
tree | f8460da2806c6f233a5d5572cd2524c11ab792bd | |
parent | 9ea5a37c46eee072faf1c1dff1e941fae24f86c4 (diff) |
Report corpus counts, add --gdb option
-rwxr-xr-x | src/scripts/test_fuzzers.py | 81 |
1 files changed, 66 insertions, 15 deletions
diff --git a/src/scripts/test_fuzzers.py b/src/scripts/test_fuzzers.py index 0d473e00c..5b5fbc5a8 100755 --- a/src/scripts/test_fuzzers.py +++ b/src/scripts/test_fuzzers.py @@ -3,13 +3,49 @@ import sys import os import subprocess +import optparse +import stat + +def run_fuzzer(fuzzer_bin, corpus_file, run_under_gdb): + + if run_under_gdb: + gdb_proc = subprocess.Popen(['gdb', '--quiet', '--return-child-result', fuzzer_bin], + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + close_fds=True) + + gdb_commands = ('run < %s\nbt\nquit\n' % (corpus_file)).encode('ascii') + + (stdout, stderr) = gdb_proc.communicate(gdb_commands) + + if gdb_proc.returncode == 0: + return (0, '', '') + + return (gdb_proc.returncode, stdout.decode('ascii'), stderr.decode('ascii')) + else: + corpus_fd = open(corpus_file, 'r') + fuzzer_proc = subprocess.Popen([fuzzer_bin], stdin=corpus_fd, + stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True) + (stdout, stderr) = fuzzer_proc.communicate() + corpus_fd.close() + return (fuzzer_proc.returncode, stdout.decode('ascii'), stderr.decode('ascii')) def main(args=None): if args is None: args = sys.argv + parser = optparse.OptionParser( + usage='Usage: %prog [options] corpus_dir fuzzers_dir', + ) + + parser.add_option('--gdb', action='store_true', + help='Run under GDB and capture backtraces') + + (options, args) = parser.parse_args(args) + if len(args) != 3: - print("Usage: %s <corpus_dir> <fuzzers_dir>" % (args[0])) + parser.print_usage() return 1 corpus_dir = args[1] @@ -31,8 +67,13 @@ def main(args=None): corpii = set([]) for corpus in os.listdir(corpus_dir): - if corpus in ['.git', 'readme.txt']: + # Ignore regular files in toplevel dir + if not stat.S_ISDIR(os.stat(os.path.join(corpus_dir, corpus)).st_mode): + continue + + if corpus == '.git': continue + corpii.add(corpus) fuzzers_without_corpus = fuzzers - corpii @@ -45,34 +86,44 @@ def main(args=None): fuzzers_with_corpus = fuzzers & corpii - any_crashes = False + crash_count = 0 + stderr_count = 0 + stdout_count = 0 + + gdb_commands = None for f in sorted(list(fuzzers_with_corpus)): fuzzer_bin = os.path.join(fuzzer_dir, f) corpus_files = os.path.join(corpus_dir, f) + + tests_for_this_fuzzer = 0 + for corpus_file in sorted(list(os.listdir(corpus_files))): - corpus_fd = open(os.path.join(corpus_files, corpus_file), 'r') - fuzzer_proc = subprocess.Popen([fuzzer_bin], stdin=corpus_fd, - stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True) - (stdout, stderr) = fuzzer_proc.communicate() - corpus_fd.close() - if fuzzer_proc.returncode != 0: - print("Fuzzer %s crashed with input %s returncode %d" % (f, corpus_file, fuzzer_proc.returncode)) - any_crashes = True + tests_for_this_fuzzer += 1 + + corpus_full_path = os.path.join(corpus_files, corpus_file) + + (retcode, stdout, stderr) = run_fuzzer(fuzzer_bin, corpus_full_path, options.gdb) + + if retcode != 0: + print("Fuzzer %s crashed with input %s returncode %d" % (f, corpus_file, retcode)) + crash_count += 1 if len(stdout) != 0: - stdout = stdout.decode('ascii') print("Fuzzer %s produced stdout on input %s:\n%s" % (f, corpus_file, stdout)) + stdout_count += 1 if len(stderr) != 0: - stderr = stderr.decode('ascii') print("Fuzzer %s produced stderr on input %s:\n%s" % (f, corpus_file, stderr)) + stderr_count += 1 - if any_crashes: + print("Tested fuzzer %s with %d test cases, %d crashes" % (f, tests_for_this_fuzzer, crash_count)) + + if crash_count > 0 or stderr_count > 0 or stdout_count > 0: + print("Ran fuzzer tests, %d crashes %d stdout %d stderr" % (crash_count, stdout_count, stderr_count)) return 2 return 0 - if __name__ == '__main__': sys.exit(main()) |