diff --git a/tests/fuzz.py b/tests/fuzz.py index 8d46b1c..7f9bfe4 100644 --- a/tests/fuzz.py +++ b/tests/fuzz.py @@ -9,9 +9,7 @@ below `REPLACE_DICT`. import os import subprocess -import itertools import argparse -import sys import re import random from pathlib import Path @@ -26,40 +24,47 @@ REPLACE_DICT = { r"__attribute__\s*\(\(.*\)\)": "", "_Float128": "double", "long double": "double", - "(\+[0-9^FL]*)L": r"\1", + r"(\+[0-9^FL]*)L": r"\1", "union": "struct", r"enum[\w\s]*\{[^\}]*\};": "", r"typedef enum[\w\s]*\{[^;]*;[\s_A-Z]*;": "", - "const char \*const sys_errlist\[\];": "", # ArraySize::Unknown 삭제 + r"const char \*const sys_errlist\[\];": "", # ArraySize::Unknown 삭제 r"[^\n]*printf[^;]*;": "", r"[^\n]*scanf[^;]*;": "", " restrict": "", "inline ": "", "_Nullable": "", - "\"g_\w*\", ": "", # transparent_crc에서 프린트 목적으로 받은 StringLiteral 삭제 - "char\* vname, ": "", # transparent_crc에서 사용하지 않는 파라미터 삭제 - r"transparent_crc_bytes\s*\([^;]*\);": "", # transparent_crc_bytes 삭제 - r"[^\n]*_IO_2_1_[^;]*;": "", # extern을 지우면서 생긴 size를 알 수 없는 struct 삭제 - r"__asm\s*\([^\)]*\)": "", # asm extension in mac - r"__asm__\s*\([^\)]*\)": "", # asm extension in linux + r'"g_\w*", ': "", # transparent_crc에서 프린트 목적으로 받은 StringLiteral 삭제 + r"char\* vname, ": "", # transparent_crc에서 사용하지 않는 파라미터 삭제 + r"transparent_crc_bytes\s*\([^;]*\);": "", # transparent_crc_bytes 삭제 + r"[^\n]*_IO_2_1_[^;]*;": "", # extern을 지우면서 생긴 size를 알 수 없는 struct 삭제 + r"__asm\s*\([^\)]*\)": "", # asm extension in mac + r"__asm__\s*\([^\)]*\)": "", # asm extension in linux "typedef __builtin_va_list __gnuc_va_list;": "", "typedef __gnuc_va_list va_list;": "", r"\(fabsf\(": "((", - # todo: need to consider the case below in the future: # avoid compile-time constant expressed as complex expression such as `1 + 1` - "char _unused2[^;]*;": "char _unused2[10];", + "char _unused2[^;]*;": "char _unused2[10];", } CSMITH_DIR = "csmith-2.3.0" SKIP_TEST = 102 + class ProgressBar: def __init__(self): self.stage = 0 - self.stage_indicators = ["-", "\\", "|", "/", ] - self.pbar = tqdm.tqdm(total=1, bar_format="{l_bar}{bar}| [Elapsed:{elapsed}, 0 print("Fuzzing with {} test cases.".format(num_iter)) @@ -279,16 +344,21 @@ def fuzz(tests_dir, fuzz_arg, num_iter, easy): while True: print("Test case #{} (skipped: {})".format(i, skip)) src = generate(tests_dir, csmith_bin, random.randint(1, 987654321), easy) - with open(os.path.join(tests_dir, "test.c"), 'w') as dst: + with open(os.path.join(tests_dir, "test.c"), "w") as dst: dst.write(src) src_polished = polish(src, csmith_inc) - with open(os.path.join(tests_dir, "test_polished.c"), 'w') as dst: + with open(os.path.join(tests_dir, "test_polished.c"), "w") as dst: dst.write(src_polished) try: args = [fuzz_bin, fuzz_arg, os.path.join(tests_dir, "test_polished.c")] - proc = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, cwd=tests_dir) + proc = subprocess.Popen( + args, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + cwd=tests_dir, + ) proc.communicate(timeout=60) # KECC sets an exit code of 102 when the test skipped. @@ -296,11 +366,16 @@ def fuzz(tests_dir, fuzz_arg, num_iter, easy): skip += 1 continue elif proc.returncode != 0: - raise Exception("Test `{}` failed with exit code {}.".format(" ".join(args), proc.returncode)) + raise Exception( + "Test `{}` failed with exit code {}.".format( + " ".join(args), proc.returncode + ) + ) i += 1 if num_iter is not None: - if i > num_iter: break + if i > num_iter: + break except subprocess.TimeoutExpired as e: proc.kill() skip += 1 @@ -308,21 +383,38 @@ def fuzz(tests_dir, fuzz_arg, num_iter, easy): proc.terminate() print("\n[Ctrl+C] interrupted") + if __name__ == "__main__": - parser = argparse.ArgumentParser(description='Fuzzing KECC.') - parser.add_argument('-n', '--num', type=int, help='The number of tests') - parser.add_argument('-p', '--print', action='store_true', help='Fuzzing C AST printer') - parser.add_argument('-i', '--irgen', action='store_true', help='Fuzzing irgen') - parser.add_argument('-r', '--reduce', action='store_true', help="Reducing input file") - parser.add_argument('--skip-build', action='store_true', help="Skipping cargo build") - parser.add_argument('--easy', action='store_true', help="Generate more easy code by csmith option") - parser.add_argument('--seed', type=int, help="Provide seed of fuzz generation", default=-1) - parser.add_argument('--clang-analyze', action='store_true', help="Use clang static analyzer for reducing. It prevents undefined behaviors coming from reduced program, but perhaps take a long time to do so") + parser = argparse.ArgumentParser(description="Fuzzing KECC.") + parser.add_argument("-n", "--num", type=int, help="The number of tests") + parser.add_argument( + "-p", "--print", action="store_true", help="Fuzzing C AST printer" + ) + parser.add_argument("-i", "--irgen", action="store_true", help="Fuzzing irgen") + parser.add_argument( + "-r", "--reduce", action="store_true", help="Reducing input file" + ) + parser.add_argument( + "--skip-build", action="store_true", help="Skipping cargo build" + ) + parser.add_argument( + "--easy", action="store_true", help="Generate more easy code by csmith option" + ) + parser.add_argument( + "--seed", type=int, help="Provide seed of fuzz generation", default=-1 + ) + parser.add_argument( + "--clang-analyze", + action="store_true", + help="Use clang static analyzer for reducing. It prevents undefined behaviors coming from reduced program, but perhaps take a long time to do so", + ) args = parser.parse_args() if args.print and args.irgen: - raise Exception("Choose an option used for fuzzing: '--print' or '--irgen', NOT both") - + raise Exception( + "Choose an option used for fuzzing: '--print' or '--irgen', NOT both" + ) + if args.print: fuzz_arg = "-p" elif args.irgen: @@ -331,26 +423,41 @@ if __name__ == "__main__": raise Exception("Specify fuzzing argument") if args.seed != -1: - print('Set seed as', args.seed) + print("Set seed as", args.seed) random.seed(args.seed) else: - print('Use default random seed') + print("Use default random seed") tests_dir = os.path.abspath(os.path.dirname(__file__)) if not args.skip_build: print("Building KECC..") try: - proc = subprocess.Popen(["cargo", "build", "--features=build-bin", "--release", "--bin", "fuzz", "--bin", "kecc"], cwd=tests_dir) + proc = subprocess.Popen( + [ + "cargo", + "build", + "--features=build-bin", + "--release", + "--bin", + "fuzz", + "--bin", + "kecc", + ], + cwd=tests_dir, + ) proc.communicate() except subprocess.TimeoutExpired as e: proc.kill() raise e else: - print("Skip building. Please run `cargo build --features=build-bin --release --bin fuzz --bin kecc` to manually build.") + print( + "Skip building. Please run `cargo build --features=build-bin --release --bin fuzz --bin kecc` to manually build." + ) if args.reduce: import tqdm + creduce(tests_dir, fuzz_arg, args.clang_analyze) else: fuzz(tests_dir, fuzz_arg, args.num, args.easy)