OLD | NEW |
---|---|
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. |
3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
5 | 5 |
6 """Sets environment variables needed to run a chromium unit test.""" | 6 """Sets environment variables needed to run a chromium unit test.""" |
7 | 7 |
8 import os | 8 import os |
9 import stat | 9 import stat |
10 import subprocess | 10 import subprocess |
(...skipping 17 matching lines...) Expand all Loading... | |
28 if not chrome_sandbox_path: | 28 if not chrome_sandbox_path: |
29 chrome_sandbox_path = CHROME_SANDBOX_PATH | 29 chrome_sandbox_path = CHROME_SANDBOX_PATH |
30 extra_env[CHROME_SANDBOX_ENV] = chrome_sandbox_path | 30 extra_env[CHROME_SANDBOX_ENV] = chrome_sandbox_path |
31 | 31 |
32 return extra_env | 32 return extra_env |
33 | 33 |
34 | 34 |
35 def trim_cmd(cmd): | 35 def trim_cmd(cmd): |
36 """Removes internal flags from cmd since they're just used to communicate from | 36 """Removes internal flags from cmd since they're just used to communicate from |
37 the host machine to this script running on the swarm slaves.""" | 37 the host machine to this script running on the swarm slaves.""" |
38 internal_flags = frozenset(['--asan=0', '--asan=1', '--lsan=0', '--lsan=1']) | 38 internal_flags = frozenset(['--asan=0', '--asan=1', '--lsan=0', '--lsan=1', |
Alexander Potapenko
2015/02/04 10:51:46
Shall we replace this with a list comprehension?
earthdok
2015/02/04 14:34:47
Done.
| |
39 '--msan=0', '--msan=1', '--tsan=0', '--tsan=1']) | |
39 return [i for i in cmd if i not in internal_flags] | 40 return [i for i in cmd if i not in internal_flags] |
40 | 41 |
41 | 42 |
42 def fix_python_path(cmd): | 43 def fix_python_path(cmd): |
43 """Returns the fixed command line to call the right python executable.""" | 44 """Returns the fixed command line to call the right python executable.""" |
44 out = cmd[:] | 45 out = cmd[:] |
45 if out[0] == 'python': | 46 if out[0] == 'python': |
46 out[0] = sys.executable | 47 out[0] = sys.executable |
47 elif out[0].endswith('.py'): | 48 elif out[0].endswith('.py'): |
48 out.insert(0, sys.executable) | 49 out.insert(0, sys.executable) |
49 return out | 50 return out |
50 | 51 |
51 | 52 |
52 def get_asan_env(cmd, lsan): | 53 def get_sanitizer_env(cmd, asan, lsan, msan, tsan): |
Alexander Potapenko
2015/02/04 10:51:46
I think having a separate var for each sanitizer s
earthdok
2015/02/04 14:34:47
Your suggestion?
We could use a dict, but that wo
Alexander Potapenko
2015/02/04 16:31:04
Acknowledged.
| |
53 """Returns the envirnoment flags needed for ASan and LSan.""" | 54 """Returns the envirnoment flags needed for sanitizer tools.""" |
54 | 55 |
55 extra_env = {} | 56 extra_env = {} |
56 | 57 |
57 # Instruct GTK to use malloc while running ASan or LSan tests. | 58 # Instruct GTK to use malloc while running sanitizer-instrumented tests. |
58 extra_env['G_SLICE'] = 'always-malloc' | 59 extra_env['G_SLICE'] = 'always-malloc' |
59 | 60 |
60 extra_env['NSS_DISABLE_ARENA_FREE_LIST'] = '1' | 61 extra_env['NSS_DISABLE_ARENA_FREE_LIST'] = '1' |
61 extra_env['NSS_DISABLE_UNLOAD'] = '1' | 62 extra_env['NSS_DISABLE_UNLOAD'] = '1' |
62 | 63 |
63 # TODO(glider): remove the symbolizer path once | 64 # TODO(glider): remove the symbolizer path once |
64 # https://code.google.com/p/address-sanitizer/issues/detail?id=134 is fixed. | 65 # https://code.google.com/p/address-sanitizer/issues/detail?id=134 is fixed. |
65 symbolizer_path = os.path.abspath(os.path.join(ROOT_DIR, 'third_party', | 66 symbolizer_path = os.path.abspath(os.path.join(ROOT_DIR, 'third_party', |
66 'llvm-build', 'Release+Asserts', 'bin', 'llvm-symbolizer')) | 67 'llvm-build', 'Release+Asserts', 'bin', 'llvm-symbolizer')) |
67 | 68 |
68 asan_options = [] | 69 if lsan or tsan: |
69 if lsan: | |
70 asan_options.append('detect_leaks=1') | |
71 if sys.platform == 'linux2': | |
72 # Use the debug version of libstdc++ under LSan. If we don't, there will | |
73 # be a lot of incomplete stack traces in the reports. | |
74 extra_env['LD_LIBRARY_PATH'] = '/usr/lib/x86_64-linux-gnu/debug:' | |
75 | |
76 # LSan is not sandbox-compatible, so we can use online symbolization. In | 70 # LSan is not sandbox-compatible, so we can use online symbolization. In |
77 # fact, it needs symbolization to be able to apply suppressions. | 71 # fact, it needs symbolization to be able to apply suppressions. |
78 symbolization_options = ['symbolize=1', | 72 symbolization_options = ['symbolize=1', |
79 'external_symbolizer_path=%s' % symbolizer_path] | 73 'external_symbolizer_path=%s' % symbolizer_path] |
80 | 74 elif asan or msan: |
81 suppressions_file = os.path.join(ROOT_DIR, 'tools', 'lsan', | |
82 'suppressions.txt') | |
83 lsan_options = ['suppressions=%s' % suppressions_file, | |
84 'print_suppressions=1'] | |
85 extra_env['LSAN_OPTIONS'] = ' '.join(lsan_options) | |
86 else: | |
87 # ASan uses a script for offline symbolization. | 75 # ASan uses a script for offline symbolization. |
88 # Important note: when running ASan with leak detection enabled, we must use | 76 # Important note: when running ASan with leak detection enabled, we must use |
89 # the LSan symbolization options above. | 77 # the LSan symbolization options above. |
90 symbolization_options = ['symbolize=0'] | 78 symbolization_options = ['symbolize=0'] |
91 # Set the path to llvm-symbolizer to be used by asan_symbolize.py | 79 # Set the path to llvm-symbolizer to be used by asan_symbolize.py |
92 extra_env['LLVM_SYMBOLIZER_PATH'] = symbolizer_path | 80 extra_env['LLVM_SYMBOLIZER_PATH'] = symbolizer_path |
93 | 81 |
94 asan_options.extend(symbolization_options) | 82 if asan: |
83 asan_options = symbolization_options[:] | |
84 if lsan: | |
85 asan_options.append('detect_leaks=1') | |
95 | 86 |
96 extra_env['ASAN_OPTIONS'] = ' '.join(asan_options) | 87 extra_env['ASAN_OPTIONS'] = ' '.join(asan_options) |
earthdok
2015/02/03 17:56:52
Alex: do we need replace_intrin/strict_memcmp here
Alexander Potapenko
2015/02/04 10:51:46
I think it's fine to omit them. Linux and Mac alre
| |
97 | 88 |
98 if sys.platform == 'darwin': | 89 if sys.platform == 'darwin': |
99 isolate_output_dir = os.path.abspath(os.path.dirname(cmd[0])) | 90 isolate_output_dir = os.path.abspath(os.path.dirname(cmd[0])) |
100 # This is needed because the test binary has @executable_path embedded in it | 91 # This is needed because the test binary has @executable_path embedded in |
101 # it that the OS tries to resolve to the cache directory and not the mapped | 92 # it that the OS tries to resolve to the cache directory and not the |
102 # directory. | 93 # mapped directory. |
103 extra_env['DYLD_LIBRARY_PATH'] = str(isolate_output_dir) | 94 extra_env['DYLD_LIBRARY_PATH'] = str(isolate_output_dir) |
95 | |
96 if lsan: | |
earthdok
2015/02/03 17:56:52
Currently we run LSan on top of ASan. The logic he
Alexander Potapenko
2015/02/04 10:51:46
I don't think we ever want to run LSan without ASa
| |
97 if asan or msan: | |
98 lsan_options = [] | |
99 else: | |
100 lsan_options += symbolization_options[:] | |
101 if sys.platform == 'linux2': | |
102 # Use the debug version of libstdc++ under LSan. If we don't, there will | |
103 # be a lot of incomplete stack traces in the reports. | |
104 extra_env['LD_LIBRARY_PATH'] = '/usr/lib/x86_64-linux-gnu/debug:' | |
105 | |
106 suppressions_file = os.path.join(ROOT_DIR, 'tools', 'lsan', | |
107 'suppressions.txt') | |
108 lsan_options += ['suppressions=%s' % suppressions_file, | |
109 'print_suppressions=1'] | |
110 extra_env['LSAN_OPTIONS'] = ' '.join(lsan_options) | |
111 | |
112 if msan: | |
113 msan_options = symbolization_options[:] | |
114 if lsan: | |
115 msan_options.append('detect_leaks=1') | |
116 extra_env['MSAN_OPTIONS'] = ' '.join(msan_options) | |
117 | |
118 if tsan: | |
119 tsan_options = symbolization_options[:] | |
120 extra_env['TSAN_OPTIONS'] = ' '.join(tsan_options) | |
104 | 121 |
105 return extra_env | 122 return extra_env |
106 | 123 |
107 | 124 |
108 def get_sanitizer_symbolize_command(json_path=None): | 125 def get_sanitizer_symbolize_command(json_path=None): |
109 """Construct the command to invoke offline symbolization script.""" | 126 """Construct the command to invoke offline symbolization script.""" |
110 script_path = '../tools/valgrind/asan/asan_symbolize.py' | 127 script_path = '../tools/valgrind/asan/asan_symbolize.py' |
111 cmd = [sys.executable, script_path] | 128 cmd = [sys.executable, script_path] |
112 if json_path is not None: | 129 if json_path is not None: |
113 cmd.append('--test-summary-json-file=%s' % json_path) | 130 cmd.append('--test-summary-json-file=%s' % json_path) |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
152 # Many tests assume a English interface... | 169 # Many tests assume a English interface... |
153 extra_env['LANG'] = 'en_US.UTF-8' | 170 extra_env['LANG'] = 'en_US.UTF-8' |
154 # Used by base/base_paths_linux.cc as an override. Just make sure the default | 171 # Used by base/base_paths_linux.cc as an override. Just make sure the default |
155 # logic is used. | 172 # logic is used. |
156 env.pop('CR_SOURCE_ROOT', None) | 173 env.pop('CR_SOURCE_ROOT', None) |
157 extra_env.update(get_sandbox_env(env)) | 174 extra_env.update(get_sandbox_env(env)) |
158 | 175 |
159 # Copy logic from tools/build/scripts/slave/runtest.py. | 176 # Copy logic from tools/build/scripts/slave/runtest.py. |
160 asan = '--asan=1' in cmd | 177 asan = '--asan=1' in cmd |
161 lsan = '--lsan=1' in cmd | 178 lsan = '--lsan=1' in cmd |
162 use_symbolization_script = asan and not lsan | 179 msan = '--msan=1' in cmd |
180 tsan = '--tsan=1' in cmd | |
181 use_symbolization_script = (asan or msan) and not lsan | |
163 | 182 |
164 if asan: | 183 if asan or lsan or msan or tsan: |
165 extra_env.update(get_asan_env(cmd, lsan)) | 184 extra_env.update(get_sanitizer_env(cmd, asan, lsan, msan, tsan)) |
166 # ASan is not yet sandbox-friendly on Windows (http://crbug.com/382867). | 185 |
167 if sys.platform == 'win32': | 186 if lsan or tsan or (asan and sys.platform == 'win32'): |
187 # ASan is not yet sandbox-friendly on Windows (http://crbug.com/382867). | |
188 # LSan and TSan are not sandbox-friendly. | |
168 cmd.append('--no-sandbox') | 189 cmd.append('--no-sandbox') |
169 if lsan: | |
170 cmd.append('--no-sandbox') | |
171 | 190 |
172 cmd = trim_cmd(cmd) | 191 cmd = trim_cmd(cmd) |
173 | 192 |
174 # Ensure paths are correctly separated on windows. | 193 # Ensure paths are correctly separated on windows. |
175 cmd[0] = cmd[0].replace('/', os.path.sep) | 194 cmd[0] = cmd[0].replace('/', os.path.sep) |
176 cmd = fix_python_path(cmd) | 195 cmd = fix_python_path(cmd) |
177 | 196 |
178 print('Additional test environment:\n%s\n' | 197 print('Additional test environment:\n%s\n' |
179 'Command: %s\n' % ( | 198 'Command: %s\n' % ( |
180 '\n'.join(' %s=%s' % | 199 '\n'.join(' %s=%s' % |
(...skipping 20 matching lines...) Expand all Loading... | |
201 print >> sys.stderr, 'Failed to start %s' % cmd | 220 print >> sys.stderr, 'Failed to start %s' % cmd |
202 raise | 221 raise |
203 | 222 |
204 | 223 |
205 def main(): | 224 def main(): |
206 return run_executable(sys.argv[1:], os.environ.copy()) | 225 return run_executable(sys.argv[1:], os.environ.copy()) |
207 | 226 |
208 | 227 |
209 if __name__ == '__main__': | 228 if __name__ == '__main__': |
210 sys.exit(main()) | 229 sys.exit(main()) |
OLD | NEW |