blob: 56cdf02d15285fbb22d3b51502cae3d0a849cf92 [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
29from common.common import GetJackClassPath
30from common.common import RetCode
31from common.common import RunCommand
32
33
34#
35# Tester class.
36#
37
38
39class DexFuzzTester(object):
Aart Bik842a4f32016-09-21 15:45:18 -070040 """Tester that feeds JFuzz programs into DexFuzz testing."""
Aart Bike0347482016-09-20 14:34:13 -070041
42 def __init__(self, num_tests, num_inputs, device):
43 """Constructor for the tester.
44
45 Args:
46 num_tests: int, number of tests to run
Aart Bik842a4f32016-09-21 15:45:18 -070047 num_inputs: int, number of JFuzz programs to generate
Aart Bike0347482016-09-20 14:34:13 -070048 device: string, target device serial number (or None)
49 """
50 self._num_tests = num_tests
51 self._num_inputs = num_inputs
52 self._device = device
53 self._save_dir = None
54 self._results_dir = None
55 self._dexfuzz_dir = None
56 self._inputs_dir = None
57
58 def __enter__(self):
59 """On entry, enters new temp directory after saving current directory.
60
61 Raises:
62 FatalError: error when temp directory cannot be constructed
63 """
64 self._save_dir = os.getcwd()
65 self._results_dir = mkdtemp(dir='/tmp/')
66 self._dexfuzz_dir = mkdtemp(dir=self._results_dir)
67 self._inputs_dir = mkdtemp(dir=self._dexfuzz_dir)
68 if self._results_dir is None or self._dexfuzz_dir is None or \
69 self._inputs_dir is None:
70 raise FatalError('Cannot obtain temp directory')
71 os.chdir(self._dexfuzz_dir)
72 return self
73
74 def __exit__(self, etype, evalue, etraceback):
75 """On exit, re-enters previously saved current directory and cleans up."""
76 os.chdir(self._save_dir)
77 # TODO: detect divergences or shutil.rmtree(self._results_dir)
78
79 def Run(self):
Aart Bik842a4f32016-09-21 15:45:18 -070080 """Feeds JFuzz programs into DexFuzz testing."""
Aart Bike0347482016-09-20 14:34:13 -070081 print()
Aart Bik842a4f32016-09-21 15:45:18 -070082 print('**\n**** JFuzz Testing\n**')
Aart Bike0347482016-09-20 14:34:13 -070083 print()
84 print('#Tests :', self._num_tests)
85 print('Device :', self._device)
86 print('Directory :', self._results_dir)
87 print()
Aart Bik842a4f32016-09-21 15:45:18 -070088 self.GenerateJFuzzPrograms()
Aart Bike0347482016-09-20 14:34:13 -070089 self.RunDexFuzz()
90
91
Aart Bik842a4f32016-09-21 15:45:18 -070092 def GenerateJFuzzPrograms(self):
93 """Generates JFuzz programs.
Aart Bike0347482016-09-20 14:34:13 -070094
95 Raises:
96 FatalError: error when generation fails
97 """
98 os.chdir(self._inputs_dir)
99 for i in range(1, self._num_inputs + 1):
100 jack_args = ['-cp', GetJackClassPath(), '--output-dex', '.', 'Test.java']
Aart Bik842a4f32016-09-21 15:45:18 -0700101 if RunCommand(['jfuzz'], out='Test.java', err=None) != RetCode.SUCCESS:
102 raise FatalError('Unexpected error while running JFuzz')
Aart Bike0347482016-09-20 14:34:13 -0700103 if RunCommand(['jack'] + jack_args, out=None, err='jackerr.txt',
104 timeout=30) != RetCode.SUCCESS:
105 raise FatalError('Unexpected error while running Jack')
106 shutil.move('Test.java', '../Test' + str(i) + '.java')
107 shutil.move('classes.dex', 'classes' + str(i) + '.dex')
108 os.unlink('jackerr.txt')
109
110 def RunDexFuzz(self):
111 """Starts the DexFuzz testing."""
112 os.chdir(self._dexfuzz_dir)
113 os.environ['ANDROID_DATA'] = self._dexfuzz_dir
114 dexfuzz_args = ['--inputs=' + self._inputs_dir, '--execute',
115 '--execute-class=Test', '--repeat=' + str(self._num_tests),
116 '--dump-output', '--interpreter', '--optimizing']
117 if self._device is not None:
118 dexfuzz_args += ['--device=' + self._device, '--allarm']
119 else:
120 dexfuzz_args += ['--host'] # Assume host otherwise.
121 check_call(['dexfuzz'] + dexfuzz_args)
122 # TODO: summarize findings.
123
124
125def main():
126 # Handle arguments.
127 parser = argparse.ArgumentParser()
128 parser.add_argument('--num_tests', default=10000,
129 type=int, help='number of tests to run')
130 parser.add_argument('--num_inputs', default=50,
Aart Bik842a4f32016-09-21 15:45:18 -0700131 type=int, help='number of JFuzz program to generate')
Aart Bike0347482016-09-20 14:34:13 -0700132 parser.add_argument('--device', help='target device serial number')
133 args = parser.parse_args()
134 # Run the DexFuzz tester.
135 with DexFuzzTester(args.num_tests, args.num_inputs, args.device) as fuzzer:
136 fuzzer.Run()
137
138if __name__ == '__main__':
139 main()