blob: 50c4f20aa7b30d6f1b29b77dff45eb3aa6289a87 [file] [log] [blame]
Aart Bike0347482016-09-20 14:34:13 -07001#!/usr/bin/env python3.4
2#
3# Copyright (C) 2016 The Android Open Source Project
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16
17import argparse
18import os
19import shutil
20import sys
21
22from subprocess import check_call
23from tempfile import mkdtemp
24
25sys.path.append(os.path.dirname(os.path.dirname(
26 os.path.realpath(__file__))))
27
28from common.common import FatalError
Wojciech Staszkiewicz5219fdc2016-09-29 15:12:48 -070029from common.common import GetEnvVariableOrError
Aart Bike0347482016-09-20 14:34:13 -070030from common.common import GetJackClassPath
31from common.common import RetCode
32from common.common import RunCommand
33
34
35#
36# Tester class.
37#
38
39
40class DexFuzzTester(object):
Aart Bik842a4f32016-09-21 15:45:18 -070041 """Tester that feeds JFuzz programs into DexFuzz testing."""
Aart Bike0347482016-09-20 14:34:13 -070042
43 def __init__(self, num_tests, num_inputs, device):
44 """Constructor for the tester.
45
46 Args:
47 num_tests: int, number of tests to run
Aart Bik842a4f32016-09-21 15:45:18 -070048 num_inputs: int, number of JFuzz programs to generate
Aart Bike0347482016-09-20 14:34:13 -070049 device: string, target device serial number (or None)
50 """
51 self._num_tests = num_tests
52 self._num_inputs = num_inputs
53 self._device = device
54 self._save_dir = None
55 self._results_dir = None
56 self._dexfuzz_dir = None
57 self._inputs_dir = None
Wojciech Staszkiewicz5219fdc2016-09-29 15:12:48 -070058 self._dexfuzz_env = None
Aart Bike0347482016-09-20 14:34:13 -070059
60 def __enter__(self):
61 """On entry, enters new temp directory after saving current directory.
62
63 Raises:
64 FatalError: error when temp directory cannot be constructed
65 """
66 self._save_dir = os.getcwd()
67 self._results_dir = mkdtemp(dir='/tmp/')
68 self._dexfuzz_dir = mkdtemp(dir=self._results_dir)
69 self._inputs_dir = mkdtemp(dir=self._dexfuzz_dir)
70 if self._results_dir is None or self._dexfuzz_dir is None or \
71 self._inputs_dir is None:
72 raise FatalError('Cannot obtain temp directory')
Wojciech Staszkiewicz5219fdc2016-09-29 15:12:48 -070073 self._dexfuzz_env = os.environ.copy()
74 self._dexfuzz_env['ANDROID_DATA'] = self._dexfuzz_dir
75 top = GetEnvVariableOrError('ANDROID_BUILD_TOP')
76 self._dexfuzz_env['PATH'] = (top + '/art/tools/bisection_search:' +
77 self._dexfuzz_env['PATH'])
Aart Bike0347482016-09-20 14:34:13 -070078 os.chdir(self._dexfuzz_dir)
Wojciech Staszkiewicz5219fdc2016-09-29 15:12:48 -070079 os.mkdir('divergent_programs')
80 os.mkdir('bisection_outputs')
Aart Bike0347482016-09-20 14:34:13 -070081 return self
82
83 def __exit__(self, etype, evalue, etraceback):
84 """On exit, re-enters previously saved current directory and cleans up."""
85 os.chdir(self._save_dir)
86 # TODO: detect divergences or shutil.rmtree(self._results_dir)
87
88 def Run(self):
Aart Bik842a4f32016-09-21 15:45:18 -070089 """Feeds JFuzz programs into DexFuzz testing."""
Aart Bike0347482016-09-20 14:34:13 -070090 print()
Aart Bik842a4f32016-09-21 15:45:18 -070091 print('**\n**** JFuzz Testing\n**')
Aart Bike0347482016-09-20 14:34:13 -070092 print()
93 print('#Tests :', self._num_tests)
94 print('Device :', self._device)
95 print('Directory :', self._results_dir)
96 print()
Aart Bik842a4f32016-09-21 15:45:18 -070097 self.GenerateJFuzzPrograms()
Aart Bike0347482016-09-20 14:34:13 -070098 self.RunDexFuzz()
99
100
Aart Bik842a4f32016-09-21 15:45:18 -0700101 def GenerateJFuzzPrograms(self):
102 """Generates JFuzz programs.
Aart Bike0347482016-09-20 14:34:13 -0700103
104 Raises:
105 FatalError: error when generation fails
106 """
107 os.chdir(self._inputs_dir)
108 for i in range(1, self._num_inputs + 1):
109 jack_args = ['-cp', GetJackClassPath(), '--output-dex', '.', 'Test.java']
Aart Bik842a4f32016-09-21 15:45:18 -0700110 if RunCommand(['jfuzz'], out='Test.java', err=None) != RetCode.SUCCESS:
111 raise FatalError('Unexpected error while running JFuzz')
Aart Bike0347482016-09-20 14:34:13 -0700112 if RunCommand(['jack'] + jack_args, out=None, err='jackerr.txt',
113 timeout=30) != RetCode.SUCCESS:
114 raise FatalError('Unexpected error while running Jack')
115 shutil.move('Test.java', '../Test' + str(i) + '.java')
116 shutil.move('classes.dex', 'classes' + str(i) + '.dex')
117 os.unlink('jackerr.txt')
118
119 def RunDexFuzz(self):
120 """Starts the DexFuzz testing."""
121 os.chdir(self._dexfuzz_dir)
Aart Bike0347482016-09-20 14:34:13 -0700122 dexfuzz_args = ['--inputs=' + self._inputs_dir, '--execute',
123 '--execute-class=Test', '--repeat=' + str(self._num_tests),
Wojciech Staszkiewicz5219fdc2016-09-29 15:12:48 -0700124 '--dump-output', '--interpreter', '--optimizing',
125 '--bisection-search']
Aart Bike0347482016-09-20 14:34:13 -0700126 if self._device is not None:
127 dexfuzz_args += ['--device=' + self._device, '--allarm']
128 else:
129 dexfuzz_args += ['--host'] # Assume host otherwise.
Wojciech Staszkiewicz5219fdc2016-09-29 15:12:48 -0700130 check_call(['dexfuzz'] + dexfuzz_args, env=self._dexfuzz_env)
Aart Bike0347482016-09-20 14:34:13 -0700131 # TODO: summarize findings.
132
133
134def main():
135 # Handle arguments.
136 parser = argparse.ArgumentParser()
137 parser.add_argument('--num_tests', default=10000,
138 type=int, help='number of tests to run')
139 parser.add_argument('--num_inputs', default=50,
Aart Bik842a4f32016-09-21 15:45:18 -0700140 type=int, help='number of JFuzz program to generate')
Aart Bike0347482016-09-20 14:34:13 -0700141 parser.add_argument('--device', help='target device serial number')
142 args = parser.parse_args()
143 # Run the DexFuzz tester.
144 with DexFuzzTester(args.num_tests, args.num_inputs, args.device) as fuzzer:
145 fuzzer.Run()
146
147if __name__ == '__main__':
148 main()