diff --git a/llvm/lib/Support/raw_socket_stream.cpp b/llvm/lib/Support/raw_socket_stream.cpp index cdf793c8958f..d708b35673c7 100644 --- a/llvm/lib/Support/raw_socket_stream.cpp +++ b/llvm/lib/Support/raw_socket_stream.cpp @@ -61,6 +61,21 @@ static std::error_code getLastSocketErrorCode() { #endif } +#ifdef _WIN32 +using NativeSocket = SOCKET; +#else +using NativeSocket = int; +#define INVALID_SOCKET -1 +#endif + +static int closeSocket(NativeSocket Socket) { +#ifdef _WIN32 + return ::closesocket(Socket); +#else + return ::close(Socket); +#endif +} + static Expected setSocketAddr(StringRef SocketPath) { struct sockaddr_un Addr; memset(&Addr, 0, sizeof(Addr)); @@ -76,13 +91,8 @@ static Expected setSocketAddr(StringRef SocketPath) { } static Expected getSocketFD(StringRef SocketPath) { -#ifdef _WIN32 - SOCKET Socket = socket(AF_UNIX, SOCK_STREAM, 0); + NativeSocket Socket = socket(AF_UNIX, SOCK_STREAM, 0); if (Socket == INVALID_SOCKET) { -#else - int Socket = socket(AF_UNIX, SOCK_STREAM, 0); - if (Socket == -1) { -#endif // _WIN32 return llvm::make_error(getLastSocketErrorCode(), "Create socket failed"); } @@ -97,13 +107,16 @@ static Expected getSocketFD(StringRef SocketPath) { setsockopt(Socket, SOL_SOCKET, SO_PEERCRED, NULL, 0); #endif Expected Addr = setSocketAddr(SocketPath); - if (!Addr) + if (!Addr) { + closeSocket(Socket); return Addr.takeError(); + } if (::connect(Socket, (struct sockaddr *)&*Addr, sizeof(*Addr)) == -1) { - ::close(Socket); - return llvm::make_error(getLastSocketErrorCode(), - "Connect socket failed"); + // Grab the error code before closing, which may overwrite it. + std::error_code EC = getLastSocketErrorCode(); + closeSocket(Socket); + return llvm::make_error(EC, "Connect socket failed"); } #ifdef _WIN32 @@ -158,12 +171,9 @@ Expected ListeningSocket::createUnix(StringRef SocketPath, #ifdef _WIN32 WSABalancer _; - SOCKET Socket = socket(AF_UNIX, SOCK_STREAM, 0); +#endif // _WIN32 + NativeSocket Socket = socket(AF_UNIX, SOCK_STREAM, 0); if (Socket == INVALID_SOCKET) -#else - int Socket = socket(AF_UNIX, SOCK_STREAM, 0); - if (Socket == -1) -#endif return llvm::make_error(getLastSocketErrorCode(), "socket create failed"); @@ -177,13 +187,15 @@ Expected ListeningSocket::createUnix(StringRef SocketPath, setsockopt(Socket, SOL_SOCKET, SO_PEERCRED, NULL, 0); #endif Expected Addr = setSocketAddr(SocketPath); - if (!Addr) + if (!Addr) { + closeSocket(Socket); return Addr.takeError(); + } if (::bind(Socket, (struct sockaddr *)&*Addr, sizeof(*Addr)) == -1) { - // Grab error code from call to ::bind before calling ::close + // Grab error code from call to ::bind before closing the socket std::error_code EC = getLastSocketErrorCode(); - ::close(Socket); + closeSocket(Socket); return llvm::make_error(EC, "Bind error"); } diff --git a/llvm/unittests/Support/raw_socket_stream_test.cpp b/llvm/unittests/Support/raw_socket_stream_test.cpp index 293be53a25d2..673ef4f6b3e9 100644 --- a/llvm/unittests/Support/raw_socket_stream_test.cpp +++ b/llvm/unittests/Support/raw_socket_stream_test.cpp @@ -99,6 +99,16 @@ TEST_F(raw_socket_streamTest, ACCEPT_WITH_TIMEOUT) { std::errc::timed_out); } +TEST_F(raw_socket_streamTest, CONNECT_FAILURE_RETURNS_ERROR) { + ServerListener->shutdown(); + + // Connecting to a closed or nonexistent socket should return an error, + // not terminate the process while cleaning up the temporary native socket. + Expected> MaybeClient = + raw_socket_stream::createConnectedUnix(SocketPath); + ASSERT_THAT_EXPECTED(MaybeClient, llvm::Failed()); +} + TEST_F(raw_socket_streamTest, ACCEPT_WITH_SHUTDOWN) { // Create a separate thread to close the socket after a delay. Simulates a // signal handler calling ServerListener::shutdown