Index: lldb/test/API/lldbtest.py =================================================================== --- lldb/test/API/lldbtest.py +++ lldb/test/API/lldbtest.py @@ -29,6 +29,50 @@ if not os.path.isdir(path): raise OSError(errno.ENOTDIR, "%s is not a directory"%path) +# On macOS, we can't do the DYLD_INSERT_LIBRARIES trick with a shim python +# binary as the ASan interceptors get loaded too late. Also, when SIP is +# enabled, we can't inject libraries into system binaries at all, so we need a +# copy of the "real" python to work with. +def get_darwin_python_interpreter(builddir, executable): + # Avoid doing any work if we already copied the binary. This serves as + # synchronization between multiple API tests. + copied_python = os.path.join(builddir, 'copied-python') + if os.path.isfile(copied_python): + return copied_python + + # Find the "real" python binary. + import shutil, subprocess + real_python = subprocess.check_output([ + executable, + os.path.join(os.path.dirname(os.path.realpath(__file__)), + 'get_darwin_real_python.py') + ]).decode('utf-8').strip() + + # Copy over the real python to a temporary python. We can't put it in the + # right place yet, because that might race with other tests running + # concurrently. + temp_python = os.path.join(builddir, 'copied-python') + shutil.copy(real_python, temp_python) + + # Now make sure the copied Python works. The Python in Xcode has a relative + # RPATH and cannot be copied. + try: + # We don't care about the output, just make sure it runs. + subprocess.check_output([temp_python, '-V'], + stderr=subprocess.STDOUT) + except subprocess.CalledProcessError: + # The copied Python didn't work. Assume we're dealing with the Python + # interpreter in Xcode. Given that this is not a system binary SIP + # won't prevent us form injecting the interceptors so we get away + # without using the copy. + return real_python + + # The copied Python works. Time to put it in place and start using it from + # now on. + shutil.copy(temp_python, copied_python) + return copied_python + + class LLDBTest(TestFormat): def __init__(self, dotest_cmd): self.dotest_cmd = dotest_cmd @@ -75,25 +119,9 @@ builddir = getBuildDir(cmd) mkdir_p(builddir) - - # On macOS, we can't do the DYLD_INSERT_LIBRARIES trick with a shim - # python binary as the ASan interceptors get loaded too late. Also, - # when SIP is enabled, we can't inject libraries into system binaries - # at all, so we need a copy of the "real" python to work with. - # - # Find the "real" python binary, copy it, and invoke it. if 'DYLD_INSERT_LIBRARIES' in test.config.environment and \ platform.system() == 'Darwin': - copied_python = os.path.join(builddir, 'copied-system-python') - if not os.path.isfile(copied_python): - import shutil, subprocess - python = subprocess.check_output([ - executable, - os.path.join(os.path.dirname(os.path.realpath(__file__)), - 'get_darwin_real_python.py') - ]).decode('utf-8').strip() - shutil.copy(python, copied_python) - cmd[0] = copied_python + cmd[0] = get_darwin_python_interpreter(builddir, executable) if 'lldb-repro-capture' in test.config.available_features or \ 'lldb-repro-replay' in test.config.available_features: