Apply SOCK_CLOEXEC flag to socket API functions in order to avoid handle leakage to a forked child process.

http://reviews.llvm.org/D6204

llvm-svn: 222004
diff --git a/lldb/source/Host/common/Socket.cpp b/lldb/source/Host/common/Socket.cpp
index ba99bdf..a6118ee 100644
--- a/lldb/source/Host/common/Socket.cpp
+++ b/lldb/source/Host/common/Socket.cpp
@@ -55,6 +55,33 @@
 #endif
 #endif // #ifdef __ANDROID__
 
+namespace {
+
+NativeSocket CreateSocket(const int domain, const int type, const int protocol, bool child_processes_inherit)
+{
+    auto socketType = type;
+#ifdef SOCK_CLOEXEC
+    if (!child_processes_inherit) {
+        socketType |= SOCK_CLOEXEC;
+    }
+#endif
+    return ::socket (domain, socketType, protocol);
+}
+
+NativeSocket Accept(NativeSocket sockfd, struct sockaddr *addr, socklen_t *addrlen, bool child_processes_inherit)
+{
+#ifdef SOCK_CLOEXEC
+    int flags = 0;
+    if (!child_processes_inherit) {
+        flags |= SOCK_CLOEXEC;
+    }
+    return ::accept4 (sockfd, addr, addrlen, flags);
+#else
+    return ::accept (sockfd, addr, addrlen);
+#endif
+}
+}
+
 Socket::Socket(NativeSocket socket, SocketProtocol protocol, bool should_close)
     : IOObject(eFDTypeSocket, should_close)
     , m_protocol(protocol)
@@ -68,7 +95,7 @@
     Close();
 }
 
-Error Socket::TcpConnect(llvm::StringRef host_and_port, Socket *&socket)
+Error Socket::TcpConnect(llvm::StringRef host_and_port, bool child_processes_inherit, Socket *&socket)
 {
     // Store the result in a unique_ptr in case we error out, the memory will get correctly freed.
     std::unique_ptr<Socket> final_socket;
@@ -86,7 +113,7 @@
         return error;
 
     // Create the socket
-    sock = ::socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
+    sock = CreateSocket (AF_INET, SOCK_STREAM, IPPROTO_TCP, child_processes_inherit);
     if (sock == kInvalidSocketValue)
     {
         // TODO: On Windows, use WSAGetLastError().
@@ -140,7 +167,7 @@
     return error;
 }
 
-Error Socket::TcpListen(llvm::StringRef host_and_port, Socket *&socket, Predicate<uint16_t>* predicate)
+Error Socket::TcpListen(llvm::StringRef host_and_port, bool child_processes_inherit, Socket *&socket, Predicate<uint16_t>* predicate)
 {
     std::unique_ptr<Socket> listen_socket;
     NativeSocket listen_sock = kInvalidSocketValue;
@@ -149,7 +176,7 @@
     const sa_family_t family = AF_INET;
     const int socktype = SOCK_STREAM;
     const int protocol = IPPROTO_TCP;
-    listen_sock = ::socket (family, socktype, protocol);
+    listen_sock = ::CreateSocket (family, socktype, protocol, child_processes_inherit);
     if (listen_sock == kInvalidSocketValue)
     {
         error.SetErrorToErrno();
@@ -211,7 +238,7 @@
     return error;
 }
 
-Error Socket::BlockingAccept(llvm::StringRef host_and_port, Socket *&socket)
+Error Socket::BlockingAccept(llvm::StringRef host_and_port, bool child_processes_inherit, Socket *&socket)
 {
     Error error;
     std::string host_str;
@@ -250,7 +277,10 @@
 #endif
         socklen_t accept_addr_len = sizeof accept_addr;
 
-        int sock = ::accept (this->GetNativeSocket(), (struct sockaddr *)&accept_addr, &accept_addr_len);
+        int sock = Accept (this->GetNativeSocket(),
+                           (struct sockaddr *)&accept_addr,
+                           &accept_addr_len,
+                           child_processes_inherit);
             
         if (sock == kInvalidSocketValue)
         {
@@ -295,7 +325,7 @@
 
 }
 
-Error Socket::UdpConnect(llvm::StringRef host_and_port, Socket *&send_socket, Socket *&recv_socket)
+Error Socket::UdpConnect(llvm::StringRef host_and_port, bool child_processes_inherit, Socket *&send_socket, Socket *&recv_socket)
 {
     std::unique_ptr<Socket> final_send_socket;
     std::unique_ptr<Socket> final_recv_socket;
@@ -315,7 +345,7 @@
 
     // Setup the receiving end of the UDP connection on this localhost
     // on port zero. After we bind to port zero we can read the port.
-    final_recv_fd = ::socket (AF_INET, SOCK_DGRAM, 0);
+    final_recv_fd = ::CreateSocket (AF_INET, SOCK_DGRAM, 0, child_processes_inherit);
     if (final_recv_fd == kInvalidSocketValue)
     {
         // Socket creation failed...
@@ -366,9 +396,10 @@
          service_info_ptr != NULL; 
          service_info_ptr = service_info_ptr->ai_next) 
     {
-        final_send_fd = ::socket (service_info_ptr->ai_family, 
-                                  service_info_ptr->ai_socktype,
-                                  service_info_ptr->ai_protocol);
+        final_send_fd = ::CreateSocket (service_info_ptr->ai_family,
+                                        service_info_ptr->ai_socktype,
+                                        service_info_ptr->ai_protocol,
+                                        child_processes_inherit);
 
         if (final_send_fd != kInvalidSocketValue)
         {
@@ -395,7 +426,7 @@
     return error;
 }
 
-Error Socket::UnixDomainConnect(llvm::StringRef name, Socket *&socket)
+Error Socket::UnixDomainConnect(llvm::StringRef name, bool child_processes_inherit, Socket *&socket)
 {
     Error error;
 #ifndef LLDB_DISABLE_POSIX
@@ -403,7 +434,7 @@
 
     // Open the socket that was passed in as an option
     struct sockaddr_un saddr_un;
-    int fd = ::socket (AF_UNIX, SOCK_STREAM, 0);
+    int fd = ::CreateSocket (AF_UNIX, SOCK_STREAM, 0, child_processes_inherit);
     if (fd == kInvalidSocketValue)
     {
         error.SetErrorToErrno();
@@ -432,7 +463,7 @@
     return error;
 }
 
-Error Socket::UnixDomainAccept(llvm::StringRef name, Socket *&socket)
+Error Socket::UnixDomainAccept(llvm::StringRef name, bool child_processes_inherit, Socket *&socket)
 {
     Error error;
 #ifndef LLDB_DISABLE_POSIX
@@ -442,7 +473,7 @@
     NativeSocket listen_fd = kInvalidSocketValue;
     NativeSocket socket_fd = kInvalidSocketValue;
     
-    listen_fd = ::socket (AF_UNIX, SOCK_STREAM, 0);
+    listen_fd = ::CreateSocket (AF_UNIX, SOCK_STREAM, 0, child_processes_inherit);
     if (listen_fd == kInvalidSocketValue)
     {
         error.SetErrorToErrno();
@@ -464,7 +495,7 @@
     {
         if (::listen (listen_fd, 5) == 0) 
         {
-            socket_fd = ::accept (listen_fd, NULL, 0);
+            socket_fd = Accept (listen_fd, NULL, 0, child_processes_inherit);
             if (socket_fd > 0)
             {
                 final_socket.reset(new Socket(socket_fd, ProtocolUnixDomain, true));
diff --git a/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp b/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp
index f0513b8..f251e67 100644
--- a/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp
+++ b/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp
@@ -49,12 +49,13 @@
 using namespace lldb;
 using namespace lldb_private;
 
-ConnectionFileDescriptor::ConnectionFileDescriptor()
+ConnectionFileDescriptor::ConnectionFileDescriptor(bool child_processes_inherit)
     : Connection()
     , m_pipe()
     , m_mutex(Mutex::eMutexTypeRecursive)
     , m_shutting_down(false)
     , m_waiting_for_accept(false)
+    , m_child_processes_inherit(child_processes_inherit)
 {
     Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION | LIBLLDB_LOG_OBJECT));
     if (log)
@@ -67,6 +68,7 @@
     , m_mutex(Mutex::eMutexTypeRecursive)
     , m_shutting_down(false)
     , m_waiting_for_accept(false)
+    , m_child_processes_inherit(false)
 {
     m_write_sp.reset(new File(fd, owns_fd));
     m_read_sp.reset(new File(fd, false));
@@ -690,7 +692,7 @@
 ConnectionFileDescriptor::NamedSocketAccept(const char *socket_name, Error *error_ptr)
 {
     Socket *socket = nullptr;
-    Error error = Socket::UnixDomainAccept(socket_name, socket);
+    Error error = Socket::UnixDomainAccept(socket_name, m_child_processes_inherit, socket);
     if (error_ptr)
         *error_ptr = error;
     m_write_sp.reset(socket);
@@ -702,7 +704,7 @@
 ConnectionFileDescriptor::NamedSocketConnect(const char *socket_name, Error *error_ptr)
 {
     Socket *socket = nullptr;
-    Error error = Socket::UnixDomainConnect(socket_name, socket);
+    Error error = Socket::UnixDomainConnect(socket_name, m_child_processes_inherit, socket);
     if (error_ptr)
         *error_ptr = error;
     m_write_sp.reset(socket);
@@ -717,7 +719,7 @@
 
     Socket *socket = nullptr;
     m_waiting_for_accept = true;
-    Error error = Socket::TcpListen(s, socket, &m_port_predicate);
+    Error error = Socket::TcpListen(s, m_child_processes_inherit, socket, &m_port_predicate);
     if (error_ptr)
         *error_ptr = error;
     if (error.Fail())
@@ -727,7 +729,7 @@
 
     listening_socket_up.reset(socket);
     socket = nullptr;
-    error = listening_socket_up->BlockingAccept(s, socket);
+    error = listening_socket_up->BlockingAccept(s, m_child_processes_inherit, socket);
     listening_socket_up.reset();
     if (error_ptr)
         *error_ptr = error;
@@ -743,7 +745,7 @@
 ConnectionFileDescriptor::ConnectTCP(const char *s, Error *error_ptr)
 {
     Socket *socket = nullptr;
-    Error error = Socket::TcpConnect(s, socket);
+    Error error = Socket::TcpConnect(s, m_child_processes_inherit, socket);
     if (error_ptr)
         *error_ptr = error;
     m_write_sp.reset(socket);
@@ -756,7 +758,7 @@
 {
     Socket *send_socket = nullptr;
     Socket *recv_socket = nullptr;
-    Error error = Socket::UdpConnect(s, send_socket, recv_socket);
+    Error error = Socket::UdpConnect(s, m_child_processes_inherit, send_socket, recv_socket);
     if (error_ptr)
         *error_ptr = error;
     m_write_sp.reset(send_socket);
@@ -778,3 +780,15 @@
     }
     return bound_port;
 }
+
+bool
+ConnectionFileDescriptor::GetChildProcessesInherit() const
+{
+    return m_child_processes_inherit;
+}
+
+void
+ConnectionFileDescriptor::SetChildProcessesInherit(bool child_processes_inherit)
+{
+    m_child_processes_inherit = child_processes_inherit;
+}