blob: 34a92f6ea81b0883d13c35e598aab1e1b2ed96c3 [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
Aart Bik5618a572017-01-24 10:27:52 -080022from subprocess import call
Aart Bike0347482016-09-20 14:34:13 -070023from 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 Bik5618a572017-01-24 10:27:52 -080078 android_root = GetEnvVariableOrError('ANDROID_HOST_OUT')
79 self._dexfuzz_env['ANDROID_ROOT'] = android_root
80 self._dexfuzz_env['LD_LIBRARY_PATH'] = android_root + '/lib'
Aart Bike0347482016-09-20 14:34:13 -070081 os.chdir(self._dexfuzz_dir)
Wojciech Staszkiewicz5219fdc2016-09-29 15:12:48 -070082 os.mkdir('divergent_programs')
83 os.mkdir('bisection_outputs')
Aart Bike0347482016-09-20 14:34:13 -070084 return self
85
86 def __exit__(self, etype, evalue, etraceback):
87 """On exit, re-enters previously saved current directory and cleans up."""
88 os.chdir(self._save_dir)
89 # TODO: detect divergences or shutil.rmtree(self._results_dir)
90
91 def Run(self):
Aart Bik842a4f32016-09-21 15:45:18 -070092 """Feeds JFuzz programs into DexFuzz testing."""
Aart Bike0347482016-09-20 14:34:13 -070093 print()
Aart Bik842a4f32016-09-21 15:45:18 -070094 print('**\n**** JFuzz Testing\n**')
Aart Bike0347482016-09-20 14:34:13 -070095 print()
96 print('#Tests :', self._num_tests)
97 print('Device :', self._device)
98 print('Directory :', self._results_dir)
99 print()
Aart Bik842a4f32016-09-21 15:45:18 -0700100 self.GenerateJFuzzPrograms()
Aart Bike0347482016-09-20 14:34:13 -0700101 self.RunDexFuzz()
102
103
Aart Bik842a4f32016-09-21 15:45:18 -0700104 def GenerateJFuzzPrograms(self):
105 """Generates JFuzz programs.
Aart Bike0347482016-09-20 14:34:13 -0700106
107 Raises:
108 FatalError: error when generation fails
109 """
110 os.chdir(self._inputs_dir)
111 for i in range(1, self._num_inputs + 1):
112 jack_args = ['-cp', GetJackClassPath(), '--output-dex', '.', 'Test.java']
Aart Bik842a4f32016-09-21 15:45:18 -0700113 if RunCommand(['jfuzz'], out='Test.java', err=None) != RetCode.SUCCESS:
114 raise FatalError('Unexpected error while running JFuzz')
Aart Bike0347482016-09-20 14:34:13 -0700115 if RunCommand(['jack'] + jack_args, out=None, err='jackerr.txt',
116 timeout=30) != RetCode.SUCCESS:
117 raise FatalError('Unexpected error while running Jack')
118 shutil.move('Test.java', '../Test' + str(i) + '.java')
119 shutil.move('classes.dex', 'classes' + str(i) + '.dex')
120 os.unlink('jackerr.txt')
121
122 def RunDexFuzz(self):
123 """Starts the DexFuzz testing."""
124 os.chdir(self._dexfuzz_dir)
Aart Bik5618a572017-01-24 10:27:52 -0800125 dexfuzz_args = ['--inputs=' + self._inputs_dir,
126 '--execute',
127 '--execute-class=Test',
128 '--repeat=' + str(self._num_tests),
129 '--dump-output', '--dump-verify',
130 '--interpreter', '--optimizing',
Wojciech Staszkiewicz5219fdc2016-09-29 15:12:48 -0700131 '--bisection-search']
Aart Bike0347482016-09-20 14:34:13 -0700132 if self._device is not None:
133 dexfuzz_args += ['--device=' + self._device, '--allarm']
134 else:
135 dexfuzz_args += ['--host'] # Assume host otherwise.
Aart Bik5618a572017-01-24 10:27:52 -0800136 cmd = ['dexfuzz'] + dexfuzz_args
137 print('**** Running ****\n\n', cmd, '\n')
138 call(cmd, env=self._dexfuzz_env)
139 print('\n**** Results (report.log) ****\n')
140 call(['tail', '-n 24', 'report.log'])
Aart Bike0347482016-09-20 14:34:13 -0700141
142
143def main():
144 # Handle arguments.
145 parser = argparse.ArgumentParser()
Aart Bik5618a572017-01-24 10:27:52 -0800146 parser.add_argument('--num_tests', default=1000,
Aart Bike0347482016-09-20 14:34:13 -0700147 type=int, help='number of tests to run')
Aart Bik5618a572017-01-24 10:27:52 -0800148 parser.add_argument('--num_inputs', default=10,
Aart Bik842a4f32016-09-21 15:45:18 -0700149 type=int, help='number of JFuzz program to generate')
Aart Bike0347482016-09-20 14:34:13 -0700150 parser.add_argument('--device', help='target device serial number')
151 args = parser.parse_args()
152 # Run the DexFuzz tester.
153 with DexFuzzTester(args.num_tests, args.num_inputs, args.device) as fuzzer:
154 fuzzer.Run()
155
156if __name__ == '__main__':
157 main()