[Lldb-commits] [lldb] 526e0c8 - [lldb/Test] Fix ASan/TSan workaround for Xcode Python 3

Jonas Devlieghere via lldb-commits lldb-commits at lists.llvm.org
Thu Jun 11 19:36:49 PDT 2020


Author: Jonas Devlieghere
Date: 2020-06-11T19:36:42-07:00
New Revision: 526e0c8d15216e6c49b1769c63f5433df6841c64

URL: https://github.com/llvm/llvm-project/commit/526e0c8d15216e6c49b1769c63f5433df6841c64
DIFF: https://github.com/llvm/llvm-project/commit/526e0c8d15216e6c49b1769c63f5433df6841c64.diff

LOG: [lldb/Test] Fix ASan/TSan workaround for Xcode Python 3

The Python 3 interpreter in Xcode has a relative RPATH and dyld fails to
load it when we copy it into the build directory.

This patch adds an additional check that the copied binary can be
executed. If it doesn't, we assume we're dealing with the Xcode python
interpreter and return the path to the real executable. That is
sufficient for the sanitizers because only system binaries need to be
copied to work around SIP.

This patch also moves all that logic out of LLDBTest and into the lit
configuration so that it's executed only once per test run, instead of
once for every test. Although I didn't benchmark the difference this
should result in a mild speedup.

Differential revision: https://reviews.llvm.org/D81696

Added: 
    

Modified: 
    lldb/test/API/lit.cfg.py
    lldb/test/API/lit.site.cfg.py.in
    lldb/test/API/lldbtest.py

Removed: 
    


################################################################################
diff  --git a/lldb/test/API/lit.cfg.py b/lldb/test/API/lit.cfg.py
index 288d667c18dd..632d883e0da9 100644
--- a/lldb/test/API/lit.cfg.py
+++ b/lldb/test/API/lit.cfg.py
@@ -21,6 +21,17 @@
 config.test_exec_root = config.test_source_root
 
 
+def mkdir_p(path):
+    import errno
+    try:
+        os.makedirs(path)
+    except OSError as e:
+        if e.errno != errno.EEXIST:
+            raise
+    if not os.path.isdir(path):
+        raise OSError(errno.ENOTDIR, "%s is not a directory"%path)
+
+
 def find_sanitizer_runtime(name):
   import subprocess
   resource_dir = subprocess.check_output(
@@ -38,6 +49,43 @@ def find_shlibpath_var():
     yield '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 find_python_interpreter():
+  # Avoid doing any work if we already copied the binary.
+  copied_python = os.path.join(config.lldb_build_directory, 'copied-python')
+  if os.path.isfile(copied_python):
+    return copied_python
+
+  # Find the "real" python binary.
+  import shutil, subprocess
+  real_python = subprocess.check_output([
+      config.python_executable,
+      os.path.join(os.path.dirname(os.path.realpath(__file__)),
+                   'get_darwin_real_python.py')
+  ]).decode('utf-8').strip()
+
+  shutil.copy(real_python, copied_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([copied_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 with
+    # not copying the executable.
+    os.remove(copied_python)
+    return real_python
+
+  # The copied Python works.
+  return copied_python
+
+
 if 'Address' in config.llvm_use_sanitizer:
   config.environment['ASAN_OPTIONS'] = 'detect_stack_use_after_return=1'
   if 'Darwin' in config.host_os and 'x86' in config.host_triple:
@@ -49,6 +97,9 @@ def find_shlibpath_var():
     config.environment['DYLD_INSERT_LIBRARIES'] = find_sanitizer_runtime(
         'libclang_rt.tsan_osx_dynamic.dylib')
 
+if 'DYLD_INSERT_LIBRARIES' in config.environment and platform.system() == 'Darwin':
+  config.python_executable = find_python_interpreter()
+
 # Shared library build of LLVM may require LD_LIBRARY_PATH or equivalent.
 if config.shared_libs:
   for shlibpath_var in find_shlibpath_var():

diff  --git a/lldb/test/API/lit.site.cfg.py.in b/lldb/test/API/lit.site.cfg.py.in
index e5d5c00c43be..e97f867b265b 100644
--- a/lldb/test/API/lit.site.cfg.py.in
+++ b/lldb/test/API/lit.site.cfg.py.in
@@ -18,6 +18,7 @@ config.shared_libs = @LLVM_ENABLE_SHARED_LIBS@
 config.llvm_use_sanitizer = "@LLVM_USE_SANITIZER@"
 config.target_triple = "@TARGET_TRIPLE@"
 config.lldb_build_directory = "@LLDB_TEST_BUILD_DIRECTORY@"
+config.lldb_reproducer_directory = os.path.join("@LLDB_TEST_BUILD_DIRECTORY@", "reproducers")
 config.python_executable = "@PYTHON_EXECUTABLE@"
 config.dotest_path = "@LLDB_SOURCE_DIR@/test/API/dotest.py"
 config.dotest_args_str = "@LLDB_DOTEST_ARGS@"

diff  --git a/lldb/test/API/lldbtest.py b/lldb/test/API/lldbtest.py
index fcc13a07eded..94eb8ebd054a 100644
--- a/lldb/test/API/lldbtest.py
+++ b/lldb/test/API/lldbtest.py
@@ -10,24 +10,6 @@
 import lit.util
 from lit.formats.base import TestFormat
 
-def getBuildDir(cmd):
-    found = False
-    for arg in cmd:
-        if found:
-            return arg
-        if arg == '--build-dir':
-            found = True
-    return None
-
-def mkdir_p(path):
-    import errno
-    try:
-        os.makedirs(path)
-    except OSError as e:
-        if e.errno != errno.EEXIST:
-            raise
-    if not os.path.isdir(path):
-        raise OSError(errno.ENOTDIR, "%s is not a directory"%path)
 
 class LLDBTest(TestFormat):
     def __init__(self, dotest_cmd):
@@ -73,33 +55,10 @@ def execute(self, test, litConfig):
         # python exe as the first parameter of the command.
         cmd = [executable] + self.dotest_cmd + [testPath, '-p', testFile]
 
-        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
-
         if 'lldb-repro-capture' in test.config.available_features or \
            'lldb-repro-replay' in test.config.available_features:
-            reproducer_root = os.path.join(builddir, 'reproducers')
-            mkdir_p(reproducer_root)
-            reproducer_path = os.path.join(reproducer_root, testFile)
+            reproducer_path = os.path.join(
+                test.config.lldb_reproducer_directory, testFile)
             if 'lldb-repro-capture' in test.config.available_features:
                 cmd.extend(['--capture-path', reproducer_path])
             else:


        


More information about the lldb-commits mailing list