1#! /usr/bin/python3 -B 2# 3# SPDX-License-Identifier: BSD-2-Clause 4# 5# Copyright (c) 2018-2021 Gavin D. Howard and contributors. 6# 7# Redistribution and use in source and binary forms, with or without 8# modification, are permitted provided that the following conditions are met: 9# 10# * Redistributions of source code must retain the above copyright notice, this 11# list of conditions and the following disclaimer. 12# 13# * Redistributions in binary form must reproduce the above copyright notice, 14# this list of conditions and the following disclaimer in the documentation 15# and/or other materials provided with the distribution. 16# 17# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 21# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27# POSSIBILITY OF SUCH DAMAGE. 28# 29 30import os 31import sys 32import shutil 33import subprocess 34 35def usage(): 36 print("usage: {} [--asan] dir [results_dir [exe options...]]".format(script)) 37 sys.exit(1) 38 39def check_crash(exebase, out, error, file, type, test): 40 if error < 0: 41 print("\n{} crashed ({}) on {}:\n".format(exebase, -error, type)) 42 print(" {}".format(test)) 43 print("\nCopying to \"{}\"".format(out)) 44 shutil.copy2(file, out) 45 print("\nexiting...") 46 sys.exit(error) 47 48def run_test(cmd, exebase, tout, indata, out, file, type, test, environ=None): 49 try: 50 p = subprocess.run(cmd, timeout=tout, input=indata, stdout=subprocess.PIPE, 51 stderr=subprocess.PIPE, env=environ) 52 check_crash(exebase, out, p.returncode, file, type, test) 53 except subprocess.TimeoutExpired: 54 print("\n {} timed out. Continuing...\n".format(exebase)) 55 56def create_test(file, tout, environ=None): 57 58 print(" {}".format(file)) 59 60 base = os.path.basename(file) 61 62 if base == "README.txt": 63 return 64 65 with open(file, "rb") as f: 66 lines = f.readlines() 67 68 print(" Running whole file...") 69 70 run_test(exe + [ file ], exebase, tout, halt.encode(), out, file, "file", file, environ) 71 72 print(" Running file through stdin...") 73 74 with open(file, "rb") as f: 75 content = f.read() 76 77 run_test(exe, exebase, tout, content, out, file, 78 "running {} through stdin".format(file), file, environ) 79 80 81def get_children(dir, get_files): 82 dirs = [] 83 with os.scandir(dir) as it: 84 for entry in it: 85 if not entry.name.startswith('.') and \ 86 ((entry.is_dir() and not get_files) or \ 87 (entry.is_file() and get_files)): 88 dirs.append(entry.name) 89 dirs.sort() 90 return dirs 91 92 93def exe_name(d): 94 return "bc" if d == "bc1" or d == "bc2" or d == "bc3" else "dc" 95 96script = sys.argv[0] 97testdir = os.path.dirname(script) 98 99if __name__ != "__main__": 100 usage() 101 102timeout = 2.5 103 104if len(sys.argv) < 2: 105 usage() 106 107idx = 1 108 109exedir = sys.argv[idx] 110 111asan = (exedir == "--asan") 112 113if asan: 114 idx += 1 115 if len(sys.argv) < idx + 1: 116 usage() 117 exedir = sys.argv[idx] 118 119print("exedir: {}".format(exedir)) 120 121if len(sys.argv) >= idx + 2: 122 resultsdir = sys.argv[idx + 1] 123else: 124 if exedir == "bc1": 125 resultsdir = testdir + "/fuzzing/bc_outputs1" 126 elif exedir == "bc2": 127 resultsdir = testdir + "/fuzzing/bc_outputs2" 128 elif exedir == "bc3": 129 resultsdir = testdir + "/fuzzing/bc_outputs3" 130 else: 131 resultsdir = testdir + "/fuzzing/dc_outputs" 132 133print("resultsdir: {}".format(resultsdir)) 134 135if len(sys.argv) >= idx + 3: 136 exe = sys.argv[idx + 2] 137else: 138 exe = testdir + "/../bin/" + exe_name(exedir) 139 140exebase = os.path.basename(exe) 141 142if exebase == "bc": 143 halt = "halt\n" 144 options = "-lq" 145else: 146 halt = "q\n" 147 options = "-x" 148 149if len(sys.argv) >= idx + 4: 150 exe = [ exe, sys.argv[idx + 3:], options ] 151else: 152 exe = [ exe, options ] 153for i in range(4, len(sys.argv)): 154 exe.append(sys.argv[i]) 155 156out = testdir + "/../.test.txt" 157 158print(os.path.realpath(os.getcwd())) 159 160dirs = get_children(resultsdir, False) 161 162if asan: 163 env = os.environ.copy() 164 env['ASAN_OPTIONS'] = 'abort_on_error=1:allocator_may_return_null=1' 165 166for d in dirs: 167 168 d = resultsdir + "/" + d 169 170 print(d) 171 172 files = get_children(d + "/crashes/", True) 173 174 for file in files: 175 file = d + "/crashes/" + file 176 create_test(file, timeout) 177 178 if not asan: 179 continue 180 181 files = get_children(d + "/queue/", True) 182 183 for file in files: 184 file = d + "/queue/" + file 185 create_test(file, timeout * 2, env) 186 187print("Done") 188 189