def CompileOnHost(self): """Compiles Test.java into classes.dex using either javac/dx or d8. Raises: FatalError: error when compilation fails """ if self._dexer == 'dx' or self._dexer == 'd8': dbg = '-g' if self._debug_info else '-g:none' if RunCommand(['javac', '--release=8', dbg, 'Test.java'], out=None, err='jerr.txt', timeout=30) != RetCode.SUCCESS: print('Unexpected error while running javac') raise FatalError('Unexpected error while running javac') cfiles = glob('*.class') dx = 'dx' if self._dexer == 'dx' else 'd8-compat-dx' if RunCommand([dx, '--dex', '--output=classes.dex'] + cfiles, out=None, err='dxerr.txt', timeout=30) != RetCode.SUCCESS: print('Unexpected error while running dx') raise FatalError('Unexpected error while running dx') # Cleanup on success (nothing to see). for cfile in cfiles: os.unlink(cfile) os.unlink('jerr.txt') os.unlink('dxerr.txt') else: raise FatalError('Unknown dexer: ' + self._dexer)
def __enter__(self): """On entry, enters new temp directory after saving current directory. Raises: FatalError: error when temp directory cannot be constructed """ self._save_dir = os.getcwd() self._results_dir = mkdtemp(dir='/tmp/') self._dexfuzz_dir = mkdtemp(dir=self._results_dir) self._inputs_dir = mkdtemp(dir=self._dexfuzz_dir) if self._results_dir is None or self._dexfuzz_dir is None or \ self._inputs_dir is None: raise FatalError('Cannot obtain temp directory') self._dexfuzz_env = os.environ.copy() self._dexfuzz_env['ANDROID_DATA'] = self._dexfuzz_dir top = GetEnvVariableOrError('ANDROID_BUILD_TOP') self._dexfuzz_env['PATH'] = (top + '/art/tools/bisection_search:' + self._dexfuzz_env['PATH']) android_root = GetEnvVariableOrError('ANDROID_HOST_OUT') self._dexfuzz_env['ANDROID_ROOT'] = android_root self._dexfuzz_env['LD_LIBRARY_PATH'] = android_root + '/lib' os.chdir(self._dexfuzz_dir) os.mkdir('divergent_programs') os.mkdir('bisection_outputs') return self
def main(): # Handle arguments. parser = argparse.ArgumentParser() parser.add_argument('--num_tests', default=10000, type=int, help='number of tests to run') parser.add_argument('--device', help='target device serial number') parser.add_argument('--mode1', default='ri', help='execution mode 1 (default: ri)') parser.add_argument('--mode2', default='hopt', help='execution mode 2 (default: hopt)') parser.add_argument('--report_script', help='script called for each' 'divergence') parser.add_argument('--jfuzz_arg', default=[], dest='jfuzz_args', action='append', help='argument for jfuzz') parser.add_argument('--true_divergence', default=False, action='store_true', help='don\'t bisect timeout divergences') args = parser.parse_args() if args.mode1 == args.mode2: raise FatalError('Identical execution modes given') # Run the JFuzz tester. with JFuzzTester(args.num_tests, args.device, args.mode1, args.mode2, args.jfuzz_args, args.report_script, args.true_divergence) as fuzzer: fuzzer.Run()
def ConstructTest(self): """Use JFuzz to generate next Test.java test. Raises: FatalError: error when jfuzz fails """ if (RunCommand(['jfuzz'] + self._jfuzz_args, out='Test.java', err=None) != RetCode.SUCCESS): raise FatalError('Unexpected error while running JFuzz')
def __enter__(self): """On entry, enters new temp directory after saving current directory. Raises: FatalError: error when temp directory cannot be constructed """ self._save_dir = os.getcwd() self._results_dir = mkdtemp(dir='/tmp/') self._jfuzz_dir = mkdtemp(dir=self._results_dir) if self._results_dir is None or self._jfuzz_dir is None: raise FatalError('Cannot obtain temp directory') os.chdir(self._jfuzz_dir) return self
def GenerateJFuzzPrograms(self): """Generates JFuzz programs. Raises: FatalError: error when generation fails """ os.chdir(self._inputs_dir) for i in range(1, self._num_inputs + 1): jack_args = [ '-cp', GetJackClassPath(), '--output-dex', '.', 'Test.java' ] if RunCommand(['jfuzz'], out='Test.java', err=None) != RetCode.SUCCESS: raise FatalError('Unexpected error while running JFuzz') if RunCommand( ['jack'] + jack_args, out=None, err='jackerr.txt', timeout=30) != RetCode.SUCCESS: raise FatalError('Unexpected error while running Jack') shutil.move('Test.java', '../Test' + str(i) + '.java') shutil.move('classes.dex', 'classes' + str(i) + '.dex') os.unlink('jackerr.txt')
def GenerateJFuzzPrograms(self): """Generates JFuzz programs. Raises: FatalError: error when generation fails """ os.chdir(self._inputs_dir) for i in range(1, self._num_inputs + 1): if RunCommand(['jfuzz'], out='Test.java', err=None) != RetCode.SUCCESS: print('Unexpected error while running JFuzz') raise FatalError('Unexpected error while running JFuzz') self.CompileOnHost() shutil.move('Test.java', '../Test' + str(i) + '.java') shutil.move('classes.dex', 'classes' + str(i) + '.dex')
def CompileOnHost(self): """Compiles Test.java into classes.dex using either javac/dx or jack. Raises: FatalError: error when compilation fails """ if self._use_dx: if RunCommand( ['javac', 'Test.java'], out=None, err='jerr.txt', timeout=30) != RetCode.SUCCESS: print('Unexpected error while running javac') raise FatalError('Unexpected error while running javac') cfiles = glob('*.class') if RunCommand(['dx', '--dex', '--output=classes.dex'] + cfiles, out=None, err='dxerr.txt', timeout=30) != RetCode.SUCCESS: print('Unexpected error while running dx') raise FatalError('Unexpected error while running dx') # Cleanup on success (nothing to see). for cfile in cfiles: os.unlink(cfile) os.unlink('jerr.txt') os.unlink('dxerr.txt') else: jack_args = [ '-cp', GetJackClassPath(), '--output-dex', '.', 'Test.java' ] if RunCommand( ['jack'] + jack_args, out=None, err='jackerr.txt', timeout=30) != RetCode.SUCCESS: print('Unexpected error while running Jack') raise FatalError('Unexpected error while running Jack') # Cleanup on success (nothing to see). os.unlink('jackerr.txt')
def GetAllMethods(self): """Get methods compiled during the test. Returns: List of strings representing methods compiled during the test. Raises: FatalError: An error occurred when retrieving methods list. """ cmd = self._PrepareCmd() (output, _) = self._test_env.RunCommand(cmd, LogSeverity.INFO) match_methods = re.findall(r'Building ([^\n]+)\n', output) if not match_methods: raise FatalError('Failed to retrieve methods list. ' 'Not recognized output format.') return match_methods
def CompileOnHost(self): if self._dexer == 'dx' or self._dexer == 'd8': dbg = '-g' if self._debug_info else '-g:none' if RunCommand(['javac', '--release=8', dbg, 'Test.java'], out=None, err=None, timeout=30) == RetCode.SUCCESS: dx = 'dx' if self._dexer == 'dx' else 'd8-compat-dx' retc = RunCommand([dx, '--dex', '--output=classes.dex'] + glob('*.class'), out=None, err='dxerr.txt', timeout=30) else: retc = RetCode.NOTCOMPILED else: raise FatalError('Unknown dexer: ' + self._dexer) return retc
def BugSearch(testable): """Find buggy (method, optimization pass) pair for a given testable. Args: testable: Dex2OatWrapperTestable. Returns: (string, string) tuple. First element is name of method which when compiled exposes test failure. Second element is name of optimization pass such that for aforementioned method running all passes up to and excluding the pass results in test passing but running all passes up to and including the pass results in test failing. (None, None) if test passes when compiling all methods. (string, None) if a method is found which exposes the failure, but the failure happens even when running just mandatory passes. Raises: FatalError: Testable fails with no methods compiled. AssertionError: Method failed for all passes when bisecting methods, but passed when bisecting passes. Possible sporadic failure. """ all_methods = testable.GetAllMethods() faulty_method_idx = BinarySearch( 0, len(all_methods) + 1, lambda mid: testable.Test(all_methods[0:mid])) if faulty_method_idx == len(all_methods) + 1: return (None, None) if faulty_method_idx == 0: raise FatalError('Testable fails with no methods compiled.') faulty_method = all_methods[faulty_method_idx - 1] all_passes = testable.GetAllPassesForMethod(faulty_method) faulty_pass_idx = BinarySearch( 0, len(all_passes) + 1, lambda mid: testable.Test([faulty_method], FilterPasses(all_passes, mid))) if faulty_pass_idx == 0: return (faulty_method, None) assert faulty_pass_idx != len(all_passes) + 1, ('Method must fail for some ' 'passes.') faulty_pass = all_passes[faulty_pass_idx - 1] return (faulty_method, faulty_pass)
def GetAllPassesForMethod(self, compiled_method): """Get all optimization passes ran for a method during the test. Args: compiled_method: string representing method to compile. Returns: List of strings representing passes ran for compiled_method during test. Raises: FatalError: An error occurred when retrieving passes list. """ cmd = self._PrepareCmd(compiled_methods=[compiled_method]) (output, _) = self._test_env.RunCommand(cmd, LogSeverity.INFO) match_passes = re.findall(r'Starting pass: ([^\n]+)\n', output) if not match_passes: raise FatalError('Failed to retrieve passes list. ' 'Not recognized output format.') return [p for p in match_passes if p not in NON_PASSES]
def GetExecutionModeRunner(device, mode): """Returns a runner for the given execution mode. Args: device: string, target device serial number (or None) mode: string, execution mode Returns: TestRunner with given execution mode Raises: FatalError: error for unknown execution mode """ if mode == 'ri': return TestRunnerRIOnHost() if mode == 'hint': return TestRunnerArtIntOnHost() if mode == 'hopt': return TestRunnerArtOptOnHost() if mode == 'tint': return TestRunnerArtIntOnTarget(device) if mode == 'topt': return TestRunnerArtOptOnTarget(device) raise FatalError('Unknown execution mode')
def GetExecutionModeRunner(dexer, debug_info, device, mode): """Returns a runner for the given execution mode. Args: dexer: string, defines dexer debug_info: boolean, if True include debugging info device: string, target device serial number (or None) mode: string, execution mode Returns: TestRunner with given execution mode Raises: FatalError: error for unknown execution mode """ if mode == 'ri': return TestRunnerRIOnHost(debug_info) if mode == 'hint': return TestRunnerArtIntOnHost(dexer, debug_info) if mode == 'hopt': return TestRunnerArtOptOnHost(dexer, debug_info) if mode == 'tint': return TestRunnerArtIntOnTarget(dexer, debug_info, device) if mode == 'topt': return TestRunnerArtOptOnTarget(dexer, debug_info, device) raise FatalError('Unknown execution mode')