[lldb] Gracefully handle sockets being unavailable (#194712)

Gracefully handle sockets being unavailable, for example because the
test suite is running in a sandboxed environment where you're not
allowed to call bind.
This commit is contained in:
Jonas Devlieghere
2026-04-28 16:27:10 -07:00
committed by GitHub
parent 710c297289
commit f09c938951
9 changed files with 66 additions and 6 deletions

View File

@@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//
#include "lldb/Host/MainLoop.h"
#include "TestingSupport/Host/SocketTestUtilities.h"
#include "TestingSupport/SubsystemRAII.h"
#include "lldb/Host/ConnectionFileDescriptor.h"
#include "lldb/Host/FileSystem.h"
@@ -28,6 +29,9 @@ public:
SubsystemRAII<FileSystem, Socket> subsystems;
void SetUp() override {
if (!HostSupportsIPv4() && !HostSupportsIPv6())
GTEST_SKIP() << "TCP sockets unavailable";
Status error;
auto listen_socket_up = std::make_unique<TCPSocket>(true);
ASSERT_TRUE(error.Success());

View File

@@ -80,12 +80,16 @@ TEST_F(SocketTest, DecodeHostAndPort) {
TEST_F(SocketTest, CreatePair) {
std::vector<std::optional<Socket::SocketProtocol>> functional_protocols = {
std::nullopt,
Socket::ProtocolTcp,
#if LLDB_ENABLE_POSIX
Socket::ProtocolUnixDomain,
Socket::ProtocolUnixAbstract,
#endif
};
if (HostSupportsIPv4() || HostSupportsIPv6())
functional_protocols.push_back(Socket::ProtocolTcp);
#if LLDB_ENABLE_POSIX
if (HostSupportsDomainSockets()) {
functional_protocols.push_back(Socket::ProtocolUnixDomain);
functional_protocols.push_back(Socket::ProtocolUnixAbstract);
}
#endif
for (auto p : functional_protocols) {
auto expected_socket_pair = Socket::CreatePair(p);
ASSERT_THAT_EXPECTED(expected_socket_pair, llvm::Succeeded());
@@ -114,6 +118,9 @@ TEST_F(SocketTest, CreatePair) {
#if LLDB_ENABLE_POSIX
TEST_F(SocketTest, DomainListenConnectAccept) {
if (!HostSupportsDomainSockets())
GTEST_SKIP() << "Domain sockets unavailable";
llvm::SmallString<64> Path;
std::error_code EC =
llvm::sys::fs::createUniqueDirectory("DomainListenConnectAccept", Path);
@@ -130,6 +137,9 @@ TEST_F(SocketTest, DomainListenConnectAccept) {
}
TEST_F(SocketTest, DomainListenGetListeningConnectionURI) {
if (!HostSupportsDomainSockets())
GTEST_SKIP() << "Domain sockets unavailable";
llvm::SmallString<64> Path;
std::error_code EC =
llvm::sys::fs::createUniqueDirectory("DomainListenConnectAccept", Path);
@@ -152,6 +162,9 @@ TEST_F(SocketTest, DomainListenGetListeningConnectionURI) {
}
TEST_F(SocketTest, DomainMainLoopAccept) {
if (!HostSupportsDomainSockets())
GTEST_SKIP() << "Domain sockets unavailable";
llvm::SmallString<64> Path;
std::error_code EC =
llvm::sys::fs::createUniqueDirectory("DomainListenConnectAccept", Path);
@@ -356,6 +369,9 @@ TEST_P(SocketTest, UDPGetConnectURI) {
#if LLDB_ENABLE_POSIX
TEST_F(SocketTest, DomainGetConnectURI) {
if (!HostSupportsDomainSockets())
GTEST_SKIP() << "Domain sockets unavailable";
llvm::SmallString<64> domain_path;
std::error_code EC = llvm::sys::fs::createUniqueDirectory(
"DomainListenConnectAccept", domain_path);
@@ -378,6 +394,9 @@ TEST_F(SocketTest, DomainGetConnectURI) {
}
TEST_F(SocketTest, DomainSocketFromBoundNativeSocket) {
if (!HostSupportsDomainSockets())
GTEST_SKIP() << "Domain sockets unavailable";
// Generate a name for the domain socket.
llvm::SmallString<64> name;
std::error_code EC = llvm::sys::fs::createUniqueDirectory(

View File

@@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//
#include "Plugins/Platform/Android/AdbClient.h"
#include "TestingSupport/Host/SocketTestUtilities.h"
#include "lldb/Host/Socket.h"
#include "lldb/Host/common/TCPSocket.h"
#include "gtest/gtest.h"
@@ -112,6 +113,9 @@ static uint16_t FindUnusedPort() {
// This test is disabled on Windows due to platform-specific socket behavior
// that causes assertion failures in TCPSocket::Listen()
TEST_F(AdbClientTest, RealTcpConnection) {
if (!HostSupportsIPv4() && !HostSupportsIPv6())
GTEST_SKIP() << "TCP sockets unavailable";
uint16_t unused_port = FindUnusedPort();
ASSERT_NE(unused_port, 0) << "Failed to find an unused port";

View File

@@ -5,5 +5,6 @@ add_lldb_unittest(AdbClientTests
PlatformAndroidTest.cpp
LINK_LIBS
lldbHostHelpers
lldbPluginPlatformAndroid
)

View File

@@ -94,7 +94,8 @@ static bool CheckIPSupport(llvm::StringRef Proto, llvm::StringRef Addr) {
handleAllErrors(std::move(Err), [&](std::unique_ptr<llvm::ECError> ECErr) {
std::error_code ec = ECErr->convertToErrorCode();
if (ec == std::make_error_code(std::errc::address_family_not_supported) ||
ec == std::make_error_code(std::errc::address_not_available))
ec == std::make_error_code(std::errc::address_not_available) ||
ec == std::make_error_code(std::errc::operation_not_permitted))
HasProtocolError = true;
});
if (HasProtocolError) {
@@ -146,3 +147,17 @@ llvm::Expected<std::string> lldb_private::GetLocalhostIP() {
return llvm::createStringError(
"Neither IPv4 nor IPv6 appear to be supported");
}
#if LLDB_ENABLE_POSIX
bool lldb_private::HostSupportsDomainSockets() {
llvm::SmallString<64> Path;
if (llvm::sys::fs::createUniqueDirectory("SocketTestCanary", Path))
return false;
llvm::sys::path::append(Path, "test");
DomainSocket sock(true);
Status status = sock.Listen(Path, 1);
llvm::sys::fs::remove(Path);
llvm::sys::fs::remove(Path.str().rsplit('/').first);
return status.Success();
}
#endif

View File

@@ -42,6 +42,9 @@ void CreateDomainConnectedSockets(llvm::StringRef path,
bool HostSupportsIPv6();
bool HostSupportsIPv4();
#if LLDB_ENABLE_POSIX
bool HostSupportsDomainSockets();
#endif
/// Returns true if the name `localhost` maps to a loopback IPv4 address.
bool HostSupportsLocalhostToIPv4();

View File

@@ -14,6 +14,7 @@ add_lldb_unittest(debugserverTests
LINK_LIBS
lldbDebugserverCommon
lldbHost
lldbHostHelpers
LLVMTestingSupport
)

View File

@@ -14,6 +14,7 @@
#include "RNBDefs.h"
#include "RNBSocket.h"
#include "TestingSupport/Host/SocketTestUtilities.h"
#include "lldb/Host/Socket.h"
#include "lldb/Host/common/TCPSocket.h"
#include "llvm/Testing/Support/Error.h"
@@ -53,6 +54,9 @@ static void ServerCallbackv4(const void *baton, in_port_t port) {
}
void TestSocketListen(const char *addr) {
if (!lldb_private::HostSupportsIPv4() && !lldb_private::HostSupportsIPv6())
GTEST_SKIP() << "TCP sockets unavailable";
// Skip IPv6 tests if there isn't a valid interafce
auto addresses = lldb_private::SocketAddress::GetAddressInfo(
addr, NULL, AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP);
@@ -85,6 +89,9 @@ TEST(RNBSocket, LoopBackListenIPv6) { TestSocketListen("::1"); }
TEST(RNBSocket, AnyListen) { TestSocketListen("*"); }
void TestSocketConnect(const char *addr) {
if (!lldb_private::HostSupportsIPv4() && !lldb_private::HostSupportsIPv6())
GTEST_SKIP() << "TCP sockets unavailable";
// Skip IPv6 tests if there isn't a valid interafce
auto addresses = lldb_private::SocketAddress::GetAddressInfo(
addr, NULL, AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP);

View File

@@ -10,6 +10,7 @@
#define LLDB_UNITTESTS_TOOLS_LLDB_SERVER_TESTS_TESTBASE_H
#include "TestClient.h"
#include "TestingSupport/Host/SocketTestUtilities.h"
#include "lldb/Host/FileSystem.h"
#include "lldb/Host/HostInfo.h"
#include "lldb/Host/Socket.h"
@@ -33,6 +34,11 @@ public:
lldb_private::FileSystem::Terminate();
}
void SetUp() override {
if (!lldb_private::HostSupportsIPv4() && !lldb_private::HostSupportsIPv6())
GTEST_SKIP() << "TCP sockets unavailable";
}
static std::string getInferiorPath(llvm::StringRef Name) {
llvm::SmallString<64> Path(LLDB_TEST_INFERIOR_PATH);
llvm::sys::path::append(Path, Name + LLDB_TEST_INFERIOR_SUFFIX);