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

Side by Side Diff: testing/test_env.py

Issue 659543003: Fix LSan on swarming. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: cleanup Created 6 years, 2 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
« base/base.isolate ('K') | « base/base.isolate ('k') | no next file » | 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 collections
9 import os 8 import os
10 import stat 9 import stat
11 import subprocess 10 import subprocess
12 import sys 11 import sys
13 12
14 # This is hardcoded to be src/ relative to this script. 13 # This is hardcoded to be src/ relative to this script.
15 ROOT_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 14 ROOT_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
16 15
17 CHROME_SANDBOX_ENV = 'CHROME_DEVEL_SANDBOX' 16 CHROME_SANDBOX_ENV = 'CHROME_DEVEL_SANDBOX'
18 CHROME_SANDBOX_PATH = '/opt/chromium/chrome_sandbox' 17 CHROME_SANDBOX_PATH = '/opt/chromium/chrome_sandbox'
(...skipping 13 matching lines...) Expand all
32 31
33 sandbox_stat = os.stat(sandbox_path) 32 sandbox_stat = os.stat(sandbox_path)
34 if ((sandbox_stat.st_mode & stat.S_ISUID) and 33 if ((sandbox_stat.st_mode & stat.S_ISUID) and
35 (sandbox_stat.st_mode & stat.S_IRUSR) and 34 (sandbox_stat.st_mode & stat.S_IRUSR) and
36 (sandbox_stat.st_mode & stat.S_IXUSR) and 35 (sandbox_stat.st_mode & stat.S_IXUSR) and
37 (sandbox_stat.st_uid == 0)): 36 (sandbox_stat.st_uid == 0)):
38 return True 37 return True
39 return False 38 return False
40 39
41 40
42 def enable_sandbox_if_required(cmd, env, verbose=False): 41 def enable_sandbox_if_required(cmd, env, extra_env, verbose=False):
43 """Checks enables the sandbox if it is required, otherwise it disables it.""" 42 """Checks enables the sandbox if it is required, otherwise it disables it."""
44 chrome_sandbox_path = env.get(CHROME_SANDBOX_ENV, CHROME_SANDBOX_PATH) 43 chrome_sandbox_path = env.get(CHROME_SANDBOX_ENV, CHROME_SANDBOX_PATH)
45 44
46 if should_enable_sandbox(cmd, chrome_sandbox_path): 45 if should_enable_sandbox(cmd, chrome_sandbox_path):
47 if verbose: 46 if verbose:
48 print 'Enabling sandbox. Setting environment variable:' 47 print 'Enabling sandbox. Setting environment variable:'
49 print ' %s="%s"' % (CHROME_SANDBOX_ENV, chrome_sandbox_path) 48 print ' %s="%s"' % (CHROME_SANDBOX_ENV, chrome_sandbox_path)
50 env[CHROME_SANDBOX_ENV] = chrome_sandbox_path 49 extra_env[CHROME_SANDBOX_ENV] = chrome_sandbox_path
51 else: 50 else:
52 if verbose: 51 if verbose:
53 print 'Disabling sandbox. Setting environment variable:' 52 print 'Disabling sandbox. Setting environment variable:'
54 print ' CHROME_DEVEL_SANDBOX=""' 53 print ' CHROME_DEVEL_SANDBOX=""'
55 env['CHROME_DEVEL_SANDBOX'] = '' 54 extra_env['CHROME_DEVEL_SANDBOX'] = ''
earthdok 2014/10/15 14:11:45 This is not good. Please pass --no-sandbox, like w
jam 2014/10/15 15:23:25 run_test.py also unsets CHROME_DEVEL_SANDBOX. so i
earthdok 2014/10/15 17:00:37 Looking at this conditional in runtest.py, there a
jam 2014/10/15 17:23:49 good point. I added it.
55
56
57 def trim_cmd(cmd):
58 # Remove these flags from cmd since they're just used to communicate from the
59 # host machine to this script running on the swarm slaves.
60 internal_commands = ['--asan=0', '--asan=1', '--lsan=0', '--lsan=1']
M-A Ruel 2014/10/15 13:08:00 internal_commands = frozenset(['--asan=0', '--asan
jam 2014/10/15 15:23:25 Done.
61 for i in internal_commands:
62 if i in cmd:
63 cmd.remove(i)
jam 2014/10/15 03:20:48 Marc-Antoine: I added this method to remove the ex
56 64
57 65
58 def fix_python_path(cmd): 66 def fix_python_path(cmd):
59 """Returns the fixed command line to call the right python executable.""" 67 """Returns the fixed command line to call the right python executable."""
60 out = cmd[:] 68 out = cmd[:]
61 if out[0] == 'python': 69 if out[0] == 'python':
62 out[0] = sys.executable 70 out[0] = sys.executable
63 elif out[0].endswith('.py'): 71 elif out[0].endswith('.py'):
64 out.insert(0, sys.executable) 72 out.insert(0, sys.executable)
65 return out 73 return out
66 74
67 75
76 def setup_asan(cmd, extra_env, lsan):
M-A Ruel 2014/10/15 13:07:59 I also prefer it to create a extra_env locally and
jam 2014/10/15 15:23:25 Done. also enable_sandbox_if_required
77 # Instruct GTK to use malloc while running ASan or LSan tests.
M-A Ruel 2014/10/15 13:07:59 """Instructs GTK ... "
jam 2014/10/15 15:23:25 that would be for the function comment right? this
78
79 # TODO(earthdok): enabling G_SLICE gives these leaks, locally and on swarming
80 #0 0x62c01b in __interceptor_malloc (/tmp/run_tha_testXukBDT/out/Release/brows er_tests+0x62c01b)
81 #1 0x7fb64ab64a38 in g_malloc /build/buildd/glib2.0-2.32.4/./glib/gmem.c:159
82
83 #extra_env['G_SLICE'] = 'always-malloc'
jam 2014/10/15 03:20:48 Sergey: I don't know why I get these leaks with G_
earthdok 2014/10/15 14:11:45 I'll take a look. It's possible that someone intro
earthdok 2014/10/15 19:57:35 Could you please link to a test run where they rep
84 extra_env['NSS_DISABLE_ARENA_FREE_LIST'] = '1'
85 extra_env['NSS_DISABLE_UNLOAD'] = '1'
86
87 # TODO(glider): remove the symbolizer path once
88 # https://code.google.com/p/address-sanitizer/issues/detail?id=134 is fixed.
89 symbolizer_path = os.path.abspath(os.path.join(ROOT_DIR, 'third_party',
90 'llvm-build', 'Release+Asserts', 'bin', 'llvm-symbolizer'))
91
92 asan_options = []
93 if lsan:
94 asan_options.append('detect_leaks=1')
95 if sys.platform == 'linux2':
96 # Use the debug version of libstdc++ under LSan. If we don't, there will
97 # be a lot of incomplete stack traces in the reports.
98 extra_env['LD_LIBRARY_PATH'] = '/usr/lib/x86_64-linux-gnu/debug:'
earthdok 2014/10/15 14:11:45 So this is probably useless to you. This points to
earthdok 2014/10/15 14:35:56 On second thought, let's change this to point to t
jam 2014/10/15 15:23:25 I just checked and the swarm slaves, based on conn
earthdok 2014/10/15 17:00:37 But does that directory contain libstc++ DSOs?
jam 2014/10/15 17:23:49 yep chrome-bot@swarm126-c4:~$ ls /usr/lib/x86_64-
99
100 # LSan is not sandbox-compatible, so we can use online symbolization. In
101 # fact, it needs symbolization to be able to apply suppressions.
102 symbolization_options = ['symbolize=1',
103 'external_symbolizer_path=%s' % symbolizer_path]
104
105 suppressions_file = os.path.join(ROOT_DIR, 'tools', 'lsan',
106 'suppressions.txt')
107 lsan_options = ['suppressions=%s' % suppressions_file,
108 'print_suppressions=1']
109 extra_env['LSAN_OPTIONS'] = ' '.join(lsan_options)
110 else:
111 # ASan uses a script for offline symbolization.
112 # Important note: when running ASan with leak detection enabled, we must use
113 # the LSan symbolization options above.
114 symbolization_options = ['symbolize=0']
115
116 asan_options.extend(symbolization_options)
117
118 extra_env['ASAN_OPTIONS'] = ' '.join(asan_options)
119
120 if sys.platform == 'darwin':
121 isolate_output_dir = os.path.abspath(os.path.dirname(cmd[0]))
122 # This is needed because the test binary has @executable_path embedded in it
123 # it that the OS tries to resolve to the cache directory and not the mapped
124 # directory.
125 extra_env['DYLD_LIBRARY_PATH'] = str(isolate_output_dir)
126
M-A Ruel 2014/10/15 13:08:00 two lines
jam 2014/10/15 15:23:25 Done.
68 def run_executable(cmd, env): 127 def run_executable(cmd, env):
69 """Runs an executable with: 128 """Runs an executable with:
70 - environment variable CR_SOURCE_ROOT set to the root directory. 129 - environment variable CR_SOURCE_ROOT set to the root directory.
71 - environment variable LANGUAGE to en_US.UTF-8. 130 - environment variable LANGUAGE to en_US.UTF-8.
72 - environment variable CHROME_DEVEL_SANDBOX set if need 131 - environment variable CHROME_DEVEL_SANDBOX set if need
73 - Reuses sys.executable automatically. 132 - Reuses sys.executable automatically.
74 """ 133 """
75 env = collections.defaultdict(str, env) 134 extra_env = {}
76 # Many tests assume a English interface... 135 # Many tests assume a English interface...
77 env['LANG'] = 'en_US.UTF-8' 136 extra_env['LANG'] = 'en_US.UTF-8'
78 # Used by base/base_paths_linux.cc as an override. Just make sure the default 137 # Used by base/base_paths_linux.cc as an override. Just make sure the default
79 # logic is used. 138 # logic is used.
80 env.pop('CR_SOURCE_ROOT', None) 139 env.pop('CR_SOURCE_ROOT', None)
81 enable_sandbox_if_required(cmd, env) 140 enable_sandbox_if_required(cmd, env, extra_env)
82 141
83 # Copy logic from tools/build/scripts/slave/runtest.py. 142 # Copy logic from tools/build/scripts/slave/runtest.py.
84 asan = '--asan=1' in cmd 143 asan = '--asan=1' in cmd
85 lsan = '--lsan=1' in cmd 144 lsan = '--lsan=1' in cmd
86 if lsan and sys.platform == 'linux2':
87 # Use the debug version of libstdc++ under LSan. If we don't, there will
88 # be a lot of incomplete stack traces in the reports.
89 env['LD_LIBRARY_PATH'] = '/usr/lib/x86_64-linux-gnu/debug:'
90 145
91 if asan and sys.platform == 'darwin': 146 if asan:
92 isolate_output_dir = os.path.abspath(os.path.dirname(cmd[0])) 147 setup_asan(cmd, extra_env, lsan)
93 # This is needed because the test binary has @executable_path embedded in it 148
94 # that the OS tries to resolve to the cache directory and not the mapped 149 trim_cmd(cmd)
95 # directory.
96 env['DYLD_LIBRARY_PATH'] = str(isolate_output_dir)
97 150
98 # Ensure paths are correctly separated on windows. 151 # Ensure paths are correctly separated on windows.
99 cmd[0] = cmd[0].replace('/', os.path.sep) 152 cmd[0] = cmd[0].replace('/', os.path.sep)
100 cmd = fix_python_path(cmd) 153 cmd = fix_python_path(cmd)
154
155 print 'test_env.py running with\n Additional test environment: %s\n' \
156 ' Command: %s\n' % (str(extra_env), str(cmd))
jam 2014/10/15 03:20:48 Marc-Antoine: Sergey brought up a good point over
M-A Ruel 2014/10/15 13:08:00 Ok, I'd prefer something like: print('test_env.py
jam 2014/10/15 15:23:25 Done.
157 env.update(extra_env or {})
101 try: 158 try:
102 if asan: 159 # See above comment regarding offline symbolization.
160 if asan and not lsan:
103 # Need to pipe to the symbolizer script. 161 # Need to pipe to the symbolizer script.
104 p1 = subprocess.Popen(cmd, env=env, stdout=subprocess.PIPE, 162 p1 = subprocess.Popen(cmd, env=env, stdout=subprocess.PIPE,
105 stderr=sys.stdout) 163 stderr=sys.stdout)
106 p2 = subprocess.Popen(["../tools/valgrind/asan/asan_symbolize.py"], 164 p2 = subprocess.Popen(["../tools/valgrind/asan/asan_symbolize.py"],
107 stdin=p1.stdout) 165 stdin=p1.stdout)
108 p1.stdout.close() # Allow p1 to receive a SIGPIPE if p2 exits. 166 p1.stdout.close() # Allow p1 to receive a SIGPIPE if p2 exits.
109 p2.wait() 167 p2.wait()
110 return p2.returncode 168 return p2.returncode
111 else: 169 else:
112 return subprocess.call(cmd, env=env) 170 return subprocess.call(cmd, env=env)
113 except OSError: 171 except OSError:
114 print >> sys.stderr, 'Failed to start %s' % cmd 172 print >> sys.stderr, 'Failed to start %s' % cmd
115 raise 173 raise
116 174
117 175
118 def main(): 176 def main():
119 return run_executable(sys.argv[1:], os.environ.copy()) 177 return run_executable(sys.argv[1:], os.environ.copy())
120 178
121 179
122 if __name__ == '__main__': 180 if __name__ == '__main__':
123 sys.exit(main()) 181 sys.exit(main())
OLDNEW
« base/base.isolate ('K') | « base/base.isolate ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698