def test_minimize_ir_minimization_possible(self): # Add an invalid codegen flag to inject an error into the running of the # sample. The error is unconditional so IR minimization should be able to # reduce the sample to a minimal function (just returns a parameter). s = sample.Sample( 'fn main(x: u8) -> u8 { -x }', sample.SampleOptions(codegen=True, codegen_args=('--invalid_flag!!!', )), sample.parse_args_batch('bits[8]:7\nbits[8]:100')) success = test_base.TempFileCleanup.SUCCESS # type: test_base.TempFileCleanup run_dir = self.create_tempdir(cleanup=success).full_path with self.assertRaises(sample_runner.SampleError): run_fuzz.run_sample(s, run_dir=run_dir) minimized_ir_path = run_fuzz.minimize_ir(s, run_dir) self.assertIsNotNone(minimized_ir_path) self.assertIn('ir_minimizer_test.sh', os.listdir(run_dir)) # Sanity check the minimized IR. with open(minimized_ir_path, 'r') as f: contents = f.read() self.assertIn('package ', contents) self.assertIn('fn ', contents) # It should be reduced to simply a literal. self.assertIn('ret literal', contents) # And verify the minimized IR parses. subprocess.check_call([PARSE_IR, minimized_ir_path])
def main(argv): if len(argv) != 2: raise app.UsageError( 'Invalid command-line arguments; want {} <crasher path>'.format( argv[0])) with gfile.open(argv[1], 'r') as f: smp = sample.Sample.from_crasher(f.read()) if FLAGS.simulator: smp = smp._replace(options=smp.options._replace( simulator=FLAGS.simulator)) run_dir = FLAGS.run_dir if FLAGS.run_dir else tempfile.mkdtemp( 'run_crasher_') print(f'Running crasher in directory {run_dir}') try: run_fuzz.run_sample(smp, run_dir) except sample_runner.SampleError: print('FAILURE') return 1 print('SUCCESS') if not FLAGS.run_dir: # Remove the directory if it is temporary. shutil.rmtree(run_dir) return 0
def test_minimize_ir_no_minimization_possible(self): # Verify that IR minimization at least generates a minimization test script # and doesn't blow up if the IR is not minimizable. In this case, "not # minimizable" means that no error is ever generated when running the # sample. s = sample.Sample('fn main(x: u8) -> u8 { -x }', sample.SampleOptions(), sample.parse_args_batch('bits[8]:7\nbits[8]:100')) success = test_base.TempFileCleanup.SUCCESS # type: test_base.TempFileCleanup run_dir = self.create_tempdir(cleanup=success).full_path run_fuzz.run_sample(s, run_dir=run_dir) self.assertIsNone(run_fuzz.minimize_ir(s, run_dir)) dir_contents = os.listdir(run_dir) self.assertIn('ir_minimizer_test.sh', dir_contents)
def test_minimize_jit_interpreter_mismatch(self): s = sample.Sample('fn main(x: u8) -> u8 { !x }', sample.SampleOptions(), sample.parse_args_batch('bits[8]:0xff\nbits[8]:0x42')) success = test_base.TempFileCleanup.SUCCESS # type: test_base.TempFileCleanup run_dir = self.create_tempdir(cleanup=success).full_path run_fuzz.run_sample(s, run_dir=run_dir) minimized_ir_path = run_fuzz.minimize_ir( s, run_dir, inject_jit_result='bits[32]:0x0') self.assertIsNotNone(minimized_ir_path) with open(minimized_ir_path, 'r') as f: contents = f.read() self.assertIn('package ', contents) self.assertIn('fn ', contents) # It should be reduced to simply a literal. self.assertIn('ret literal', contents) # And verify the minimized IR parses. subprocess.check_call([PARSE_IR, minimized_ir_path])
def do_worker_task(workerno: int, queue: Optional[mp.Queue], crash_path: Text, summary_path: Optional[Text] = None, save_temps_path: Optional[Text] = None, minimize_ir: bool = True) -> None: """Runs worker task, receiving commands from generator and executing them.""" queue = queue or multiprocess.get_user_data()[workerno] crashers = 0 calls = 0 print('---- Started worker {}'.format(workerno)) sys.stdout.flush() start = datetime.datetime.now() # Local file to write the summary information to before writing out to the # potentially remote (i.e. CNS) summary file. Avoids a potential CNS write # with every sample. Instead data is written out in batches. summary_file = os.path.join(summary_path, 'summary_%d.binarypb' % workerno) if summary_path else None summary_temp_file = tempfile.mkstemp( prefix='temp_summary_')[1] if summary_path else None i = 0 # Silence pylint warning. for i in itertools.count(): message = queue.get() if message.command == Command.STOP: break assert message.command == Command.RUN, message.command calls += len(message.sample.args_batch) run_dir = None if save_temps_path: run_dir = os.path.join(save_temps_path, str(message.sampleno)) os.makedirs(run_dir) else: run_dir = tempfile.mkdtemp(prefix='run_fuzz_') try: run_fuzz.run_sample( message.sample, run_dir, summary_file=summary_temp_file, generate_sample_ns=message.generate_sample_ns) except sample_runner.SampleError as e: crashers += 1 record_crasher(workerno, message.sampleno, minimize_ir, message.sample, run_dir, crash_path, crashers, str(e)) if summary_file and i % 25 == 0: # Append the local temporary summary file to the actual, potentially # remote one, and delete the temporary file. with gfile.open(summary_temp_file, 'rb') as f: summaries = f.read() with gfile.open(summary_file, 'ab+') as f: f.write(summaries) gfile.remove(summary_temp_file) if not save_temps_path: shutil.rmtree(run_dir) # TODO(leary): 2020-08-28 Turn this into an option. if i != 0 and i % 16 == 0: elapsed = (datetime.datetime.now() - start).total_seconds() print('---- Worker {:3}: {:8.2f} samples/s {:8.2f} calls/s'.format( workerno, i / elapsed, calls / elapsed)) sys.stdout.flush() elapsed = (datetime.datetime.now() - start).total_seconds() print( '---- Worker {:3} finished! {:3} crashers; {:8.2f} samples/s; {:8.2f} calls/s' .format(workerno, crashers, i / elapsed, calls / elapsed)) sys.stdout.flush()
def benchmark_worker(run_dir: Text, smp: sample.Sample): print('Running!') run_fuzz.run_sample(smp, run_dir)