Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(144)

Side by Side Diff: testing/test_env.py

Issue 895923002: Support MSan/TSan in test isolation and test_env.py (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « net/net_unittests.isolate ('k') | ui/app_list/app_list_unittests.isolate » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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())
OLDNEW
« no previous file with comments | « net/net_unittests.isolate ('k') | ui/app_list/app_list_unittests.isolate » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698