llvmorg-github-actions[bot] wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-lldb

Author: Raphael Isemann (Teemperor)

<details>
<summary>Changes</summary>

We sometimes run tests in sandboxed environments that deny all calls to `bind`. 
This breaks a few of our tests that e.g. use a mock GDB server or any other 
functionality involving sockets.

This patch adds a requireSocketPermission decorator (and an equivalent utility 
for unittests) that check whether we are allowed to call bind. If we aren't 
allowed to call bind, we skip the few tests that need this functionality.

---
Full diff: https://github.com/llvm/llvm-project/pull/219208.diff


16 Files Affected:

- (modified) lldb/packages/Python/lldbsuite/test/decorators.py (+25-1) 
- (modified) lldb/packages/Python/lldbsuite/test/lldbgdbclient.py (+2) 
- (modified) lldb/packages/Python/lldbsuite/test/lldbgdbproxy.py (+2) 
- (modified) 
lldb/packages/Python/lldbsuite/test/tools/lldb-server/gdbremote_testcase.py 
(+2-1) 
- (modified) lldb/test/API/commands/platform/sdk/TestPlatformSDK.py (+1) 
- (modified) lldb/test/API/commands/protocol/TestMCPUnixSocket.py (+1) 
- (modified) 
lldb/test/API/commands/target/auto-install-main-executable/TestAutoInstallMainExecutable.py
 (+1) 
- (modified) lldb/test/API/qemu/TestQemuLaunch.py (+1) 
- (modified) lldb/test/API/tools/lldb-dap/attach/TestDAP_attachByPortNum.py 
(+1) 
- (modified) lldb/test/API/tools/lldb-dap/launch/TestDAP_launch_termination.py 
(+2) 
- (modified) lldb/test/API/tools/lldb-dap/server/TestDAP_server.py (+1) 
- (modified) lldb/unittests/API/CMakeLists.txt (+1) 
- (modified) lldb/unittests/API/SBProtocolServerTest.cpp (+4) 
- (modified) lldb/unittests/SBTestingSupport/CMakeLists.txt (+1) 
- (modified) lldb/unittests/SBTestingSupport/SBTestUtilities.cpp (+12) 
- (modified) lldb/unittests/SBTestingSupport/SBTestUtilities.h (+3) 


``````````diff
diff --git a/lldb/packages/Python/lldbsuite/test/decorators.py 
b/lldb/packages/Python/lldbsuite/test/decorators.py
index 306eb20622746..70f7122c53c16 100644
--- a/lldb/packages/Python/lldbsuite/test/decorators.py
+++ b/lldb/packages/Python/lldbsuite/test/decorators.py
@@ -4,7 +4,7 @@
 from __future__ import annotations
 
 from collections.abc import Callable
-from functools import wraps
+from functools import lru_cache, wraps
 from typing import Optional
 from packaging import version
 import contextlib
@@ -13,6 +13,7 @@
 import os
 import platform
 import re
+import socket
 import sys
 import tempfile
 import subprocess
@@ -1289,6 +1290,29 @@ def requireThreadSupport(func):
     )(func)
 
 
+@lru_cache(maxsize=None)
+def _socketPermissionError() -> Optional[str]:
+    """Probe whether the host lets us open a listening socket.
+    Returns None if it does, otherwise a description of why it doesn't.
+    """
+
+    family = socket.AF_INET
+    addr = ("localhost", 0)
+    try:
+        with socket.socket(family, socket.SOCK_STREAM) as sock:
+            sock.bind(addr)
+            sock.listen(1)
+    except OSError as e:
+        return f"host does not permit opening a listening socket: {e}"
+    return None
+
+
+def requireSocketPermission(func):
+    """Mark the item as requiring permission to open a listening socket."""
+    error = _socketPermissionError()
+    return unittest.skipIf(error is not None, UnsupportedReason(error or 
""))(func)
+
+
 def skipIfTargetDoesNotSupportSharedLibraries():
     """Skip tests that require shared library (dylib/so) support."""
     platform = lldbplatformutil.getPlatform()
diff --git a/lldb/packages/Python/lldbsuite/test/lldbgdbclient.py 
b/lldb/packages/Python/lldbsuite/test/lldbgdbclient.py
index 9b2a89e934132..b8f78a0cff5d6 100644
--- a/lldb/packages/Python/lldbsuite/test/lldbgdbclient.py
+++ b/lldb/packages/Python/lldbsuite/test/lldbgdbclient.py
@@ -2,9 +2,11 @@
 import os.path
 import lldb
 from lldbsuite.test.lldbtest import *
+from lldbsuite.test.decorators import requireSocketPermission
 from lldbsuite.test.gdbclientutils import *
 
 
+@requireSocketPermission  # setUp binds a listening socket for the mock server
 class GDBRemoteTestBase(TestBase):
     """
     Base class for GDB client tests.
diff --git a/lldb/packages/Python/lldbsuite/test/lldbgdbproxy.py 
b/lldb/packages/Python/lldbsuite/test/lldbgdbproxy.py
index e886a6fb9f23e..2456dbcad03f6 100644
--- a/lldb/packages/Python/lldbsuite/test/lldbgdbproxy.py
+++ b/lldb/packages/Python/lldbsuite/test/lldbgdbproxy.py
@@ -5,11 +5,13 @@
 
 import lldb
 from lldbsuite.test.lldbtest import *
+from lldbsuite.test.decorators import requireSocketPermission
 from lldbsuite.test.gdbclientutils import *
 import lldbgdbserverutils
 from lldbsuite.support import seven
 
 
+@requireSocketPermission  # setUp binds a listening socket for the proxy server
 class GDBProxyTestBase(TestBase):
     """
     Base class for gdbserver proxy tests.
diff --git 
a/lldb/packages/Python/lldbsuite/test/tools/lldb-server/gdbremote_testcase.py 
b/lldb/packages/Python/lldbsuite/test/tools/lldb-server/gdbremote_testcase.py
index 99f278c3186d1..76b49c205795c 100644
--- 
a/lldb/packages/Python/lldbsuite/test/tools/lldb-server/gdbremote_testcase.py
+++ 
b/lldb/packages/Python/lldbsuite/test/tools/lldb-server/gdbremote_testcase.py
@@ -15,7 +15,7 @@
 import time
 from lldbsuite.test import configuration
 from lldbsuite.test.lldbtest import *
-from lldbsuite.test.decorators import skipIfWasm
+from lldbsuite.test.decorators import requireSocketPermission, skipIfWasm
 from lldbsuite.support import seven
 from lldbgdbserverutils import *
 import logging
@@ -57,6 +57,7 @@ def test_method(self, attrvalue=attrvalue):
 
 
 @skipIfWasm  # wasm uses runtime's GDB stub, not lldb-server
+@requireSocketPermission  # the tests talk to the debug monitor over a socket
 class GdbRemoteTestCaseBase(Base, metaclass=GdbRemoteTestCaseFactory):
     # Default time out in seconds. The timeout is increased tenfold under Asan.
     DEFAULT_TIMEOUT = 20 * (10 if ("ASAN_OPTIONS" in os.environ) else 1)
diff --git a/lldb/test/API/commands/platform/sdk/TestPlatformSDK.py 
b/lldb/test/API/commands/platform/sdk/TestPlatformSDK.py
index 3bffdd5e35836..18934d3a5fdb1 100644
--- a/lldb/test/API/commands/platform/sdk/TestPlatformSDK.py
+++ b/lldb/test/API/commands/platform/sdk/TestPlatformSDK.py
@@ -39,6 +39,7 @@ def port_not_available(self):
 
     @no_debug_info_test
     @requireDarwin
+    @requireSocketPermission  # debugserver listens on PORT
     @skipTestIfFn(no_debugserver)
     @skipTestIfFn(port_not_available)
     @skipIfRemote
diff --git a/lldb/test/API/commands/protocol/TestMCPUnixSocket.py 
b/lldb/test/API/commands/protocol/TestMCPUnixSocket.py
index b0d7981a4751a..03900817587c3 100644
--- a/lldb/test/API/commands/protocol/TestMCPUnixSocket.py
+++ b/lldb/test/API/commands/protocol/TestMCPUnixSocket.py
@@ -12,6 +12,7 @@
 
 class MCPUnixSocketCommandTestCase(TestBase):
     @requirePOSIX
+    @requireSocketPermission
     @skipIfRemote
     @no_debug_info_test
     def test_unix_socket(self):
diff --git 
a/lldb/test/API/commands/target/auto-install-main-executable/TestAutoInstallMainExecutable.py
 
b/lldb/test/API/commands/target/auto-install-main-executable/TestAutoInstallMainExecutable.py
index bc40e1e9baae4..080e0afca3c3a 100644
--- 
a/lldb/test/API/commands/target/auto-install-main-executable/TestAutoInstallMainExecutable.py
+++ 
b/lldb/test/API/commands/target/auto-install-main-executable/TestAutoInstallMainExecutable.py
@@ -15,6 +15,7 @@ class TestAutoInstallMainExecutable(TestBase):
     NO_DEBUG_INFO_TESTCASE = True
     SHARED_BUILD_TESTCASE = False
 
+    @requireSocketPermission  # lldb-server runs in platform mode on a socket
     @skipIfRemote
     @skipIfWindows  # This test is flaky on Windows
     def test_target_auto_install_main_executable(self):
diff --git a/lldb/test/API/qemu/TestQemuLaunch.py 
b/lldb/test/API/qemu/TestQemuLaunch.py
index 0967f3c214cb6..13e47101b430f 100644
--- a/lldb/test/API/qemu/TestQemuLaunch.py
+++ b/lldb/test/API/qemu/TestQemuLaunch.py
@@ -15,6 +15,7 @@
 @skipIfWindows
 @skipIf(archs=["arm64e"])
 @requireNotWasm("no qemu-wasm32")
+@requireSocketPermission  # the fake emulator listens on a unix socket
 class TestQemuLaunch(TestBase):
     NO_DEBUG_INFO_TESTCASE = True
 
diff --git a/lldb/test/API/tools/lldb-dap/attach/TestDAP_attachByPortNum.py 
b/lldb/test/API/tools/lldb-dap/attach/TestDAP_attachByPortNum.py
index f7b7993740469..41e1f5875e97a 100644
--- a/lldb/test/API/tools/lldb-dap/attach/TestDAP_attachByPortNum.py
+++ b/lldb/test/API/tools/lldb-dap/attach/TestDAP_attachByPortNum.py
@@ -38,6 +38,7 @@ def create_debug_server_pipe(self):
 
     @skipIfWindows
     @skipIfNetBSD  # Try enable, get_debug_server_path previously returned 
None.
+    @requireSocketPermission  # the debug server listens on the port we attach 
to
     def test_by_port(self):
         """Tests attaching to a process by port."""
         program_path = self.build_for_attach()
diff --git a/lldb/test/API/tools/lldb-dap/launch/TestDAP_launch_termination.py 
b/lldb/test/API/tools/lldb-dap/launch/TestDAP_launch_termination.py
index 50bf2fb88957c..13962b8cd47c0 100644
--- a/lldb/test/API/tools/lldb-dap/launch/TestDAP_launch_termination.py
+++ b/lldb/test/API/tools/lldb-dap/launch/TestDAP_launch_termination.py
@@ -2,6 +2,7 @@
 Test lldb-dap launch request.
 """
 
+from lldbsuite.test.decorators import requireSocketPermission
 from lldbsuite.test.tools.lldb_dap import DAPTestCaseBase
 from lldbsuite.test.tools.lldb_dap.utils import DebugAdapter
 
@@ -13,6 +14,7 @@ class TestDAP_launch_termination(DAPTestCaseBase):
 
     USE_DEFAULT_DEBUG_ADAPTER = False
 
+    @requireSocketPermission
     def test_termination_socket(self):
         adapter = self.create_server_debug_adapter(
             connection="listen://localhost:0",
diff --git a/lldb/test/API/tools/lldb-dap/server/TestDAP_server.py 
b/lldb/test/API/tools/lldb-dap/server/TestDAP_server.py
index e756499f5afe4..d5225fd627022 100644
--- a/lldb/test/API/tools/lldb-dap/server/TestDAP_server.py
+++ b/lldb/test/API/tools/lldb-dap/server/TestDAP_server.py
@@ -15,6 +15,7 @@
 from typing import Tuple
 
 
+@requireSocketPermission  # every test starts lldb-dap in listening server mode
 class TestDAP_server(lldbdap_testcase.DAPTestCaseBase):
     def start_server(
         self, connection, connection_timeout=30
diff --git a/lldb/unittests/API/CMakeLists.txt 
b/lldb/unittests/API/CMakeLists.txt
index a7db51aea4994..6a62be11cd7aa 100644
--- a/lldb/unittests/API/CMakeLists.txt
+++ b/lldb/unittests/API/CMakeLists.txt
@@ -9,6 +9,7 @@ add_lldb_unittest(APITests
 
   LINK_LIBS
     liblldb
+    lldbSBUtilityHelpers
   )
 
 # Build with -Wdocumentation. This relies on the tests including all the API
diff --git a/lldb/unittests/API/SBProtocolServerTest.cpp 
b/lldb/unittests/API/SBProtocolServerTest.cpp
index 1191c6761e549..2efad43a72555 100644
--- a/lldb/unittests/API/SBProtocolServerTest.cpp
+++ b/lldb/unittests/API/SBProtocolServerTest.cpp
@@ -9,6 +9,7 @@
 // Use the umbrella header for -Wdocumentation.
 #include "lldb/API/LLDB.h"
 
+#include "SBTestingSupport/SBTestUtilities.h"
 #include "TestingSupport/SubsystemRAII.h"
 #include "lldb/API/SBDebugger.h"
 #include "lldb/API/SBError.h"
@@ -68,6 +69,9 @@ TEST_F(SBProtocolServerTest, CreateEmptyProtocol) {
 }
 
 TEST_F(SBProtocolServerTest, StartAndStop) {
+  if (!HostSupportsListeningSockets())
+    GTEST_SKIP() << "TCP sockets unavailable";
+
   SBError error;
   SBProtocolServer server = SBProtocolServer::Create("MCP", error);
   ASSERT_TRUE(server.IsValid());
diff --git a/lldb/unittests/SBTestingSupport/CMakeLists.txt 
b/lldb/unittests/SBTestingSupport/CMakeLists.txt
index 4e259e4870a64..5a4c0bdbea8f9 100644
--- a/lldb/unittests/SBTestingSupport/CMakeLists.txt
+++ b/lldb/unittests/SBTestingSupport/CMakeLists.txt
@@ -6,6 +6,7 @@ add_lldb_library(lldbSBUtilityHelpers
     Support
   LINK_LIBS
     liblldb
+    lldbHost
     lldbUtilityHelpers
     llvm_gtest
   )
diff --git a/lldb/unittests/SBTestingSupport/SBTestUtilities.cpp 
b/lldb/unittests/SBTestingSupport/SBTestUtilities.cpp
index b22b76b33a265..8ad98ef564d1a 100644
--- a/lldb/unittests/SBTestingSupport/SBTestUtilities.cpp
+++ b/lldb/unittests/SBTestingSupport/SBTestUtilities.cpp
@@ -11,11 +11,23 @@
 #include "TestingSupport/TestUtilities.h"
 #include "lldb/API/SBStructuredData.h"
 #include "lldb/API/SBTarget.h"
+#include "lldb/Host/Socket.h"
+#include "lldb/Host/common/TCPSocket.h"
+#include "llvm/Support/Error.h"
 #include "llvm/Testing/Support/Error.h"
 #include "gtest/gtest.h"
 
 using namespace lldb_private;
 
+bool lldb_private::HostSupportsListeningSockets() {
+  llvm::Expected<std::unique_ptr<TCPSocket>> sock =
+      Socket::TcpListen("127.0.0.1:0");
+  if (sock)
+    return true;
+  llvm::consumeError(sock.takeError());
+  return false;
+}
+
 bool lldb_private::DebuggerSupportsLLVMTarget(llvm::StringRef target) {
   lldb::SBStructuredData data = lldb::SBDebugger::GetBuildConfiguration()
                                     .GetValueForKey("targets")
diff --git a/lldb/unittests/SBTestingSupport/SBTestUtilities.h 
b/lldb/unittests/SBTestingSupport/SBTestUtilities.h
index 2a8f8e12a9633..a82f0c89348bc 100644
--- a/lldb/unittests/SBTestingSupport/SBTestUtilities.h
+++ b/lldb/unittests/SBTestingSupport/SBTestUtilities.h
@@ -16,6 +16,9 @@
 
 namespace lldb_private {
 
+/// Returns true if the host permits opening a listening socket.
+bool HostSupportsListeningSockets();
+
 /// Check if the debugger supports the given platform.
 bool DebuggerSupportsLLVMTarget(llvm::StringRef target);
 

``````````

</details>


https://github.com/llvm/llvm-project/pull/219208
_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to