From 1aef59672f143ad2c805acc16db95611d98ce4b7 Mon Sep 17 00:00:00 2001 From: ayrton Date: Fri, 24 Nov 2023 08:06:22 -0700 Subject: [PATCH 1/3] Added extra options to the YAML Took 33 minutes --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 22f98f4..08af842 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ fuzzer/ +exec/ # Byte-compiled / optimized / DLL files __pycache__/ From ddc3875f56815c8b04ac29956158982e55c05cd2 Mon Sep 17 00:00:00 2001 From: ayrton Date: Fri, 24 Nov 2023 09:31:18 -0700 Subject: [PATCH 2/3] Tried to deal with strange printing and created a problem Took 1 hour 25 minutes --- ast_generator/ast_generator.py | 5 ++- ast_parser/gaz_unparser.py | 3 ++ ast_parser/general_unparser.py | 6 +++ ast_parser/python_unparser.py | 12 ++++- config.yaml | 3 ++ constants.py | 8 ++++ fuzzer.py | 3 +- gazprea_fuzzer.py | 81 +++++++++++++++++++++++----------- tester_config.json | 10 ++--- 9 files changed, 97 insertions(+), 34 deletions(-) diff --git a/ast_generator/ast_generator.py b/ast_generator/ast_generator.py index 0fc6cb5..3106c3c 100644 --- a/ast_generator/ast_generator.py +++ b/ast_generator/ast_generator.py @@ -1,4 +1,5 @@ import string +import warnings from english_words import get_english_words_set @@ -84,8 +85,8 @@ class AstGenerator: def _init_names(self): names = get_english_words_set(['web2'], alpha=True) - possible_names = filter(lambda x: self.settings['properties']['id-length']['max'] <= len(x) <= - self.settings['properties']['id-length']['max'] and not keyword.iskeyword(x), + possible_names = filter(lambda x: (self.settings['properties']['id-length']['max'] <= len(x) <= + self.settings['properties']['id-length']['max']) and not keyword.iskeyword(x), names) var_name_list = list(possible_names) var_name_len = len(var_name_list) diff --git a/ast_parser/gaz_unparser.py b/ast_parser/gaz_unparser.py index f525ec5..d46de32 100644 --- a/ast_parser/gaz_unparser.py +++ b/ast_parser/gaz_unparser.py @@ -98,3 +98,6 @@ class GazUnparser(GeneralUnparser): def format_single_arg(self, ty, name): return "{} {}".format(ty, name) + + def setup(self): + pass diff --git a/ast_parser/general_unparser.py b/ast_parser/general_unparser.py index 5c38ff0..7855163 100644 --- a/ast_parser/general_unparser.py +++ b/ast_parser/general_unparser.py @@ -69,6 +69,9 @@ class GeneralUnparser: :return: a string of valid gazprea code """ self.source = "" + + self.setup() + for node in self.xml: self.unparse_node(node) @@ -324,6 +327,9 @@ class GeneralUnparser: def format_single_arg(self, param, param1): raise NotImplementedError + def setup(self): + raise NotImplementedError + def pretty_xml(self): dom = xml.dom.minidom.parseString(ET.tostring(self.xml).decode('utf-8')) pretty: str = dom.toprettyxml() diff --git a/ast_parser/python_unparser.py b/ast_parser/python_unparser.py index 89dff3e..1434505 100644 --- a/ast_parser/python_unparser.py +++ b/ast_parser/python_unparser.py @@ -59,7 +59,7 @@ class PythonUnparser(GeneralUnparser): def __init__(self, ast: ET.Element, debug=False): super().__init__(ast, debug, endline='\n', - outstream_begin_delimiter="print(", + outstream_begin_delimiter="gprint(", outstream_end_delimiter=", end='')", function_return_type_indicator_predicate="->", loop_start_delimiter="while ", @@ -113,3 +113,13 @@ class PythonUnparser(GeneralUnparser): def unparse(self): super().unparse() self.source += "\nif __name__ == '__main__':\n main()" + + def setup(self): + self.source += ("def gprint(expr, end=''):\n" + " if type(expr) is bool:\n" + " if expr:\n" + " print('T', end=end)\n" + " else:\n" + " print('F', end=end)\n" + " else:\n" + " print(expr, end=end)\n\n") diff --git a/config.yaml b/config.yaml index f51ce79..5ad7b7a 100644 --- a/config.yaml +++ b/config.yaml @@ -90,6 +90,9 @@ misc-weights: type-qualifier-weights: const: 10 var: 60 + conditional-eval: + true: 50 + false: 50 block-termination-probability: 0.2 # probability for a block to terminate diff --git a/constants.py b/constants.py index 5c969d5..20b6250 100644 --- a/constants.py +++ b/constants.py @@ -61,3 +61,11 @@ class NoneTagException(Exception): super().__init__(message) self.xml = xml +class GazTypeError(Exception): + + def __init__(self, message, op, ty1, ty2): + super().__init__(message) + self.op = op + self.ty1 = ty1 + self.ty2 = ty2 + diff --git a/fuzzer.py b/fuzzer.py index e12f939..1e89255 100644 --- a/fuzzer.py +++ b/fuzzer.py @@ -48,8 +48,9 @@ class GazpreaFuzzer: # input = "if __name__ == '__main__':\n while True:\n pass\n" # debug with redirect_stdout(io.StringIO()) as buf: + pass # exec(str(self.ground_truth)) - exec(self.ground_truth, globals(), locals()) # FIXME the exec doesn't actually execute for some reason... + # exec(self.ground_truth, globals(), locals()) # FIXME the exec doesn't actually execute for some reason... self.out = buf.getvalue() diff --git a/gazprea_fuzzer.py b/gazprea_fuzzer.py index 9e26176..1ad7d78 100644 --- a/gazprea_fuzzer.py +++ b/gazprea_fuzzer.py @@ -15,6 +15,16 @@ import xml.etree.ElementTree as ET from constants import NoneTagException +def gprint(expr, end=''): + if type(expr) is bool: + if expr: + print('T', end=end) + else: + print('F', end=end) + else: + print(expr, end=end) + + class Fuzzer(): def __init__(self, config: str, batch: int, seed: str, file_name: str = "fuzz"): with open(config) as yaml_file: @@ -27,16 +37,31 @@ class Fuzzer(): self.fuzzer = fz.GazpreaFuzzer(config) def fuzz(self): - os.system("rm -rf fuzzer") - os.mkdir("fuzzer") - os.mkdir("fuzzer/input") - os.mkdir("fuzzer/debug") - os.mkdir("fuzzer/debug/ast_err") - os.mkdir("fuzzer/instream") - os.mkdir("fuzzer/outputs") - os.mkdir("fuzzer/ground_truth") - os.system("cp tester_config.json fuzzer/tester_config.json") - for i in range(self.batch): + base_dir = os.getcwd() + fuzzer_root = base_dir + '/fuzzer' + + fuzzer_input = fuzzer_root + '/input/fuzzer' + fuzzer_debug = fuzzer_root + '/debug' + fuzzer_asterr = fuzzer_debug + '/ast_err' + fuzzer_instream = fuzzer_root + '/instream' + fuzzer_outputs = fuzzer_root + '/outputs/fuzzer' + fuzzer_ground_truth = fuzzer_root + '/ground_truth' + + os.system(f"rm -rf {fuzzer_root}") + os.makedirs(fuzzer_root) + os.makedirs(fuzzer_input) + os.makedirs(fuzzer_debug) + os.makedirs(fuzzer_asterr) + os.makedirs(fuzzer_instream) + os.makedirs(fuzzer_outputs) + os.makedirs(fuzzer_ground_truth) + try: + os.system(f"cp tester_config.json {fuzzer_root}/tester_config.json") + except Exception as e: + pass + + i = 0 + while i < self.batch: try: self.fuzzer.fuzz() except NoneTagException as n: @@ -44,38 +69,46 @@ class Fuzzer(): warnings.warn("None Tag Exception encountered, writing stack trace and xml to debug/ast/{}.xml\n" "Look for a top-level tag or send it to Ayrton and I'll see what I can see" "".format(r)) - with open("fuzzer/debug/ast_err/{}.xml".format(r), 'w') as f: + with open(f"{fuzzer_asterr}/{r}.xml", 'w') as f: f.write(xml.dom.minidom.parseString(ET.tostring(self.fuzzer.ast).decode('utf-8')).toprettyxml()) + + i -= 1 continue dom = xml.dom.minidom.parseString(ET.tostring(self.fuzzer.ast).decode('utf-8')) pretty: str = dom.toprettyxml() - with open("fuzzer/ground_truth/{}_{}.py".format(self.file_name, i), 'w') as f: + with open("{}/{}_{}.py".format(fuzzer_ground_truth, self.file_name, i), 'w') as f: f.write(self.fuzzer.ground_truth) - with open("fuzzer/ground_truth/{}_{}.py".format(self.file_name, i), 'r') as f: - with open("fuzzer/outputs/{}_{}.out".format(self.file_name, i), 'w') as y: - with redirect_stdout(y): # Workaround for fuzzer.py:49 + with open("{}/{}_{}.py".format(fuzzer_ground_truth, self.file_name, i), 'r') as f: + with open("{}/{}_{}.out".format(fuzzer_outputs, self.file_name, i), 'w') as y: + with redirect_stdout(y): # Workaround for fuzzer.py:49 try: - exec(f.read(), globals(), locals()) - except (OverflowError, ZeroDivisionError, ValueError): - os.system("rm -f fuzzer/ground_truth/{}_{}.py".format(self.file_name, i)) + read = f.read() + exec(read, globals()) + except (OverflowError, ZeroDivisionError, ValueError, TypeError, SyntaxError): + os.system("rm -f {}/{}_{}.py".format(fuzzer_ground_truth, self.file_name, i)) + os.system("rm -f {}/{}_{}.py".format(fuzzer_outputs, self.file_name, i)) + warnings.warn("Runtime error encountered, retrying") + i -= 1 continue except KeyboardInterrupt: r = random.randint(0, 1000000) warnings.warn("Execution halted, result written to debug/ast/{}.xml\n" "".format(r)) - with open("fuzzer/debug/ast_err/{}.xml".format(r), 'w') as f: - f.write(xml.dom.minidom.parseString(ET.tostring(self.fuzzer.ast).decode('utf-8')).toprettyxml()) + with open("{}/{}.xml".format(fuzzer_asterr, r), 'w') as f: + f.write(xml.dom.minidom.parseString( + ET.tostring(self.fuzzer.ast).decode('utf-8')).toprettyxml()) sys.exit(1) - with open("fuzzer/input/{}_{}.in".format(self.file_name, i), 'w') as f: + with open("{}/{}_{}.in".format(fuzzer_input, self.file_name, i), 'w') as f: f.write(self.fuzzer.source) - with open("fuzzer/debug/{}_{}.xml".format(self.file_name, i), 'w') as f: + with open("{}/{}_{}.xml".format(fuzzer_debug, self.file_name, i), 'w') as f: f.write(pretty) - # y.write(self.fuzzer.out) + # y.write(self.fuzzer.out) # with open("fuzzer/instream/{}.in".format(i), 'w') as f: # f.write(self.fuzzer.source) # with open("fuzzer/outputs/{}.out".format(i), 'w') as f: # f.write(self.fuzzer.out) + i += 1 if __name__ == '__main__': @@ -94,5 +127,3 @@ if __name__ == '__main__': args = parser.parse_args() fuzzer = Fuzzer(config=args.config_file, batch=args.batch_size, seed=args.seed) fuzzer.fuzz() - - diff --git a/tester_config.json b/tester_config.json index 602d1ff..d88b48a 100644 --- a/tester_config.json +++ b/tester_config.json @@ -1,12 +1,12 @@ { - "inDir": "", - "outDir": "", - "inStrDir": "", + "inDir": "input", + "outDir": "outputs", + "inStrDir": "instream", "testedExecutablePaths": { - "": "" + "fuzzer": "../exec/gazc" }, "runtimes": { - "": "" + "fuzzer": "../exec/libgazrt.so" }, "toolchains": { "gazprea": [ From 1c91f6ac86ab8f68f85aacb190ab854e5aa78a84 Mon Sep 17 00:00:00 2001 From: Ayrton Date: Fri, 24 Nov 2023 15:45:38 -0700 Subject: [PATCH 3/3] Generation errors fixed or gracefully handled --- ast_generator/ast_generator.py | 26 +++++++++++++++++++++++- ast_generator/test/config.yaml | 17 +++++++++------- ast_generator/test/test_ast_generator.py | 16 +++++++++++++++ fuzzer.py | 5 +++++ gazprea_fuzzer.py | 13 +++++++++--- 5 files changed, 66 insertions(+), 11 deletions(-) diff --git a/ast_generator/ast_generator.py b/ast_generator/ast_generator.py index 3106c3c..19b8e7d 100644 --- a/ast_generator/ast_generator.py +++ b/ast_generator/ast_generator.py @@ -156,6 +156,8 @@ class AstGenerator: self.generate_return(return_type=return_type, return_value=return_value) if self.settings['generation-options']['generate-dead-code']: self.generate_statements(exclude='declaration') + + self.print_all_current_scope_vars() self.pop_scope() self.current_ast_element = parent @@ -643,7 +645,7 @@ class AstGenerator: self.comp_op_numline, self.comp_op_cutoffs, self.comp_op_options, - comparison=True) + comparison=True) #, evals=self.get_truth()) def push_scope(self, xml_element: ET.Element = None): scope = Scope(self.current_scope) @@ -899,3 +901,25 @@ class AstGenerator: self.generate_binary(op, random.choice([GAZ_INT_KEY, GAZ_FLOAT_KEY])) else: self.generate_binary(op, random.choice(expr_type)) + + def print_all_current_scope_vars(self): + for key, value in self.current_scope.symbols.items(): + if isinstance(value, Variable): + self.print_variable(value) + + def print_variable(self, var: Variable): + """ + @brief generate an outstream for a variable + + @param var: the variable to print + @return: + """ + parent = self.current_ast_element + + args = [ + ("type", GAZ_OUT_STREAM), + ] + self.make_element(GAZ_STREAM_TAG, args) + self.current_ast_element.append(var.xml) + + self.current_ast_element = parent diff --git a/ast_generator/test/config.yaml b/ast_generator/test/config.yaml index 65cb2cf..5ad7b7a 100644 --- a/ast_generator/test/config.yaml +++ b/ast_generator/test/config.yaml @@ -9,7 +9,7 @@ generation-options: max-globals: 5 # maximum number of global variables properties: max-range-length: 5 # maximum length of ranges, vectors and tuples, (AxA matrices can exist) - use-english-words: True # use english words instead of random names (this may limit the maximum number of names) + use-english-words: True # use english words instead of random names (if we run out, we switch to random) id-length: # length of identifiers min: 1 max: 5 @@ -68,12 +68,12 @@ statement-weights: # set to 0 for any statements y in-stream: 5 type-weights: - value-types: - integer: 50 - real: 50 - boolean: 50 - character: 50 - void: 10 + atomic-types: + int: 50 # TODO change these to the gaz types + float: 50 + bool: 50 + char: 50 + void: 0 # TODO add support for void composite-types: vector: 20 tuple: 5 @@ -90,6 +90,9 @@ misc-weights: type-qualifier-weights: const: 10 var: 60 + conditional-eval: + true: 50 + false: 50 block-termination-probability: 0.2 # probability for a block to terminate diff --git a/ast_generator/test/test_ast_generator.py b/ast_generator/test/test_ast_generator.py index f69949d..98fc68d 100644 --- a/ast_generator/test/test_ast_generator.py +++ b/ast_generator/test/test_ast_generator.py @@ -309,6 +309,22 @@ class TestGeneration(unittest.TestCase): return res + def test_print_all_current_scope_vars(self): + self.ast_gen.ast = ET.Element("block") + self.ast_gen.current_ast_element = self.ast_gen.ast + self.ast_gen.generate_declaration(mut='var') + self.ast_gen.generate_declaration(mut='var') + self.ast_gen.generate_declaration(mut='var') + self.ast_gen.generate_declaration(mut='var') + + self.ast_gen.print_all_current_scope_vars() + + print(ET.tostring(self.ast_gen.ast)) + + streams = self.ast_gen.ast.findall("stream") + + self.assertEqual(4, len(streams)) + def write_ast(self): dom = xml.dom.minidom.parseString(ET.tostring(self.ast_gen.ast).decode('utf-8')) pretty: str = dom.toprettyxml() diff --git a/fuzzer.py b/fuzzer.py index 1e89255..8d4b3ec 100644 --- a/fuzzer.py +++ b/fuzzer.py @@ -28,6 +28,11 @@ class GazpreaFuzzer: self.ground_truth = None self.out = None + try: + os.makedirs('debug/ast') + except FileExistsError: + pass + def fuzz(self): self.generator.generate_ast() self.write_ast() # FIXME sometimes this is none diff --git a/gazprea_fuzzer.py b/gazprea_fuzzer.py index 1ad7d78..e7d2722 100644 --- a/gazprea_fuzzer.py +++ b/gazprea_fuzzer.py @@ -61,6 +61,7 @@ class Fuzzer(): pass i = 0 + min_i = 0 while i < self.batch: try: self.fuzzer.fuzz() @@ -71,8 +72,10 @@ class Fuzzer(): "".format(r)) with open(f"{fuzzer_asterr}/{r}.xml", 'w') as f: f.write(xml.dom.minidom.parseString(ET.tostring(self.fuzzer.ast).decode('utf-8')).toprettyxml()) - - i -= 1 + if i - 1 >= min_i: + i -= 1 + else: + i = min_i continue dom = xml.dom.minidom.parseString(ET.tostring(self.fuzzer.ast).decode('utf-8')) pretty: str = dom.toprettyxml() @@ -89,7 +92,10 @@ class Fuzzer(): os.system("rm -f {}/{}_{}.py".format(fuzzer_ground_truth, self.file_name, i)) os.system("rm -f {}/{}_{}.py".format(fuzzer_outputs, self.file_name, i)) warnings.warn("Runtime error encountered, retrying") - i -= 1 + if i - 1 >= min_i: + i -= 1 + else: + i = min_i continue except KeyboardInterrupt: r = random.randint(0, 1000000) @@ -109,6 +115,7 @@ class Fuzzer(): # with open("fuzzer/outputs/{}.out".format(i), 'w') as f: # f.write(self.fuzzer.out) i += 1 + min_i = i if __name__ == '__main__':