3
3
import os
4
4
import platform
5
5
import re
6
+ import shutil
6
7
import subprocess
7
8
import tempfile
8
9
@@ -77,6 +78,75 @@ def add_runtime(name):
77
78
return ToolSubst (f"%{ name } " , find_runtime (name ))
78
79
79
80
81
+ # Provide the path to asan runtime lib 'libclang_rt.asan_osx_dynamic.dylib' if
82
+ # available. This is darwin specific since it's currently only needed on darwin.
83
+ # Stolen from llvm/test/lit.cfg.py with a few modifications
84
+ def get_asan_rtlib ():
85
+ if not "asan" in config .available_features or not "Darwin" in config .host_os :
86
+ return ""
87
+ # Find the asan rt lib
88
+ resource_dir = (
89
+ subprocess .check_output ([config .host_cc .strip (), "-print-resource-dir" ])
90
+ .decode ("utf-8" )
91
+ .strip ()
92
+ )
93
+ return os .path .join (
94
+ resource_dir , "lib" , "darwin" , "libclang_rt.asan_osx_dynamic.dylib"
95
+ )
96
+
97
+
98
+ # On macOS, we can't do the DYLD_INSERT_LIBRARIES trick with a shim python
99
+ # binary as the ASan interceptors get loaded too late. Also, when SIP is
100
+ # enabled, we can't inject libraries into system binaries at all, so we need a
101
+ # copy of the "real" python to work with.
102
+ # Stolen from lldb/test/API/lit.cfg.py with a few modifications
103
+ def find_real_python_interpreter ():
104
+ # If we're running in a virtual environment, we have to copy Python into
105
+ # the virtual environment for it to work.
106
+ if sys .prefix != sys .base_prefix :
107
+ copied_python = os .path .join (sys .prefix , "bin" , "copied-python" )
108
+ else :
109
+ copied_python = os .path .join (config .lldb_build_directory , "copied-python" )
110
+
111
+ # Avoid doing any work if we already copied the binary.
112
+ if os .path .isfile (copied_python ):
113
+ return copied_python
114
+
115
+ # Find the "real" python binary.
116
+ real_python = (
117
+ subprocess .check_output (
118
+ [
119
+ config .python_executable ,
120
+ os .path .join (
121
+ os .path .dirname (os .path .realpath (__file__ )),
122
+ "get_darwin_real_python.py" ,
123
+ ),
124
+ ]
125
+ )
126
+ .decode ("utf-8" )
127
+ .strip ()
128
+ )
129
+
130
+ shutil .copy (real_python , copied_python )
131
+
132
+ # Now make sure the copied Python works. The Python in Xcode has a relative
133
+ # RPATH and cannot be copied.
134
+ try :
135
+ # We don't care about the output, just make sure it runs.
136
+ subprocess .check_call ([copied_python , "-V" ])
137
+ except subprocess .CalledProcessError :
138
+ # The copied Python didn't work. Assume we're dealing with the Python
139
+ # interpreter in Xcode. Given that this is not a system binary SIP
140
+ # won't prevent us form injecting the interceptors, but when running in
141
+ # a virtual environment, we can't use it directly. Create a symlink
142
+ # instead.
143
+ os .remove (copied_python )
144
+ os .symlink (real_python , copied_python )
145
+
146
+ # The copied Python works.
147
+ return copied_python
148
+
149
+
80
150
llvm_config .with_system_environment (["HOME" , "INCLUDE" , "LIB" , "TMP" , "TEMP" ])
81
151
82
152
llvm_config .use_default_substitutions ()
@@ -91,6 +161,7 @@ def add_runtime(name):
91
161
"LICENSE.txt" ,
92
162
"lit.cfg.py" ,
93
163
"lit.site.cfg.py" ,
164
+ "get_darwin_real_python.py" ,
94
165
]
95
166
96
167
# Tweak the PATH to include the tools dir.
@@ -172,10 +243,30 @@ def add_runtime(name):
172
243
)
173
244
174
245
python_executable = config .python_executable
175
- # Python configuration with sanitizer requires some magic preloading. This will only work on clang/linux.
176
- # TODO: detect Darwin/Windows situation (or mark these tests as unsupported on these platforms).
177
- if "asan" in config .available_features and "Linux" in config .host_os :
178
- python_executable = f"LD_PRELOAD=$({ config .host_cxx } -print-file-name=libclang_rt.asan-{ config .host_arch } .so) { config .python_executable } "
246
+ # Python configuration with sanitizer requires some magic preloading. This will only work on clang/linux/darwin.
247
+ # TODO: detect Windows situation (or mark these tests as unsupported on these platforms).
248
+ if "asan" in config .available_features :
249
+ if "Linux" in config .host_os :
250
+ python_executable = f"LD_PRELOAD=$({ config .host_cxx } -print-file-name=libclang_rt.asan-{ config .host_arch } .so) { config .python_executable } "
251
+ if "Darwin" in config .host_os :
252
+ # Ensure we use a non-shim Python executable, for the `DYLD_INSERT_LIBRARIES`
253
+ # env variable to take effect
254
+ real_python_executable = find_real_python_interpreter ()
255
+ if real_python_executable :
256
+ python_executable = real_python_executable
257
+ lit_config .note (
258
+ "Using {} instead of {}" .format (
259
+ python_executable , config .python_executable
260
+ )
261
+ )
262
+
263
+ asan_rtlib = get_asan_rtlib ()
264
+ lit_config .note ("Using ASan rtlib {}" .format (asan_rtlib ))
265
+ config .environment ["MallocNanoZone" ] = "0"
266
+ config .environment ["ASAN_OPTIONS" ] = "detect_stack_use_after_return=1"
267
+ config .environment ["DYLD_INSERT_LIBRARIES" ] = asan_rtlib
268
+
269
+
179
270
# On Windows the path to python could contains spaces in which case it needs to be provided in quotes.
180
271
# This is the equivalent of how %python is setup in llvm/utils/lit/lit/llvm/config.py.
181
272
elif "Windows" in config .host_os :
0 commit comments