Author: Raphael Isemann Date: 2026-08-28T08:50:54+01:00 New Revision: c9b09314de6d316bd2b54bb3733ceed69aff7414
URL: https://github.com/llvm/llvm-project/commit/c9b09314de6d316bd2b54bb3733ceed69aff7414 DIFF: https://github.com/llvm/llvm-project/commit/c9b09314de6d316bd2b54bb3733ceed69aff7414.diff LOG: [lldb] Add requireSocketPermission decorator for tests that bind sockets (#219208) 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. Added: Modified: lldb/packages/Python/lldbsuite/test/decorators.py lldb/packages/Python/lldbsuite/test/lldbgdbclient.py lldb/packages/Python/lldbsuite/test/lldbgdbproxy.py lldb/packages/Python/lldbsuite/test/tools/lldb-server/gdbremote_testcase.py lldb/test/API/commands/platform/sdk/TestPlatformSDK.py lldb/test/API/commands/protocol/TestMCPUnixSocket.py lldb/test/API/commands/target/auto-install-main-executable/TestAutoInstallMainExecutable.py lldb/test/API/qemu/TestQemuLaunch.py lldb/test/API/tools/lldb-dap/attach/TestDAP_attachByPortNum.py lldb/test/API/tools/lldb-dap/launch/TestDAP_launch_termination.py lldb/test/API/tools/lldb-dap/server/TestDAP_server.py lldb/unittests/API/CMakeLists.txt lldb/unittests/API/SBProtocolServerTest.cpp lldb/unittests/SBTestingSupport/CMakeLists.txt lldb/unittests/SBTestingSupport/SBTestUtilities.cpp lldb/unittests/SBTestingSupport/SBTestUtilities.h Removed: ################################################################################ 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); _______________________________________________ lldb-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
