From b4bf1c65b72fe68f59fb411b26f5875d1ca22b54 Mon Sep 17 00:00:00 2001 From: Pavel Labath Date: Mon, 9 Feb 2015 11:37:56 +0000 Subject: [PATCH] Fix descriptor leak in multi-target debugging Summary: When debugging two targets concurrently, the pseude terminal master fd from the first one would leak into the second. This fixes the problem by setting O_CLOEXEC on the master fd. Test included. Reviewers: clayborg, vharron Subscribers: lldb-commits Differential Revision: http://reviews.llvm.org/D7466 llvm-svn: 228570 --- lldb/source/Utility/PseudoTerminal.cpp | 5 ++-- .../avoids-fd-leak/TestFdLeak.py | 23 +++++++++++++++++++ 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/lldb/source/Utility/PseudoTerminal.cpp b/lldb/source/Utility/PseudoTerminal.cpp index e90955d37d4c..55d4a9a1fc1c 100644 --- a/lldb/source/Utility/PseudoTerminal.cpp +++ b/lldb/source/Utility/PseudoTerminal.cpp @@ -239,7 +239,7 @@ PseudoTerminal::Fork (char *error_str, size_t error_len) error_str[0] = '\0'; pid_t pid = LLDB_INVALID_PROCESS_ID; - if (OpenFirstAvailableMaster (O_RDWR, error_str, error_len)) + if (OpenFirstAvailableMaster (O_RDWR | O_CLOEXEC, error_str, error_len)) { // Successfully opened our master pseudo terminal @@ -258,7 +258,8 @@ PseudoTerminal::Fork (char *error_str, size_t error_len) if (OpenSlave (O_RDWR, error_str, error_len)) { // Successfully opened slave - // We are done with the master in the child process so lets close it + + // Master FD should have O_CLOEXEC set, but let's close it just in case... CloseMasterFileDescriptor (); #if defined(TIOCSCTTY) diff --git a/lldb/test/functionalities/avoids-fd-leak/TestFdLeak.py b/lldb/test/functionalities/avoids-fd-leak/TestFdLeak.py index edc67ba632a7..795b4e651925 100644 --- a/lldb/test/functionalities/avoids-fd-leak/TestFdLeak.py +++ b/lldb/test/functionalities/avoids-fd-leak/TestFdLeak.py @@ -36,6 +36,29 @@ class AvoidsFdLeakTestCase(TestBase): self.assertTrue(process.GetExitStatus() == 0, "Process returned non-zero status. Were incorrect file descriptors passed?") + @skipIfWindows # The check for descriptor leakage needs to be implemented differently here. + def test_fd_leak_multitarget (self): + self.buildDefault() + exe = os.path.join (os.getcwd(), "a.out") + + target = self.dbg.CreateTarget(exe) + + listener = lldb.SBListener() + error = lldb.SBError() + process1 = target.Launch (listener, None, None, None, None, None, + self.get_process_working_directory(), 0, True, # stop at entry + error) + self.assertTrue(process1, PROCESS_IS_VALID) + self.assertTrue(process1.GetState() == lldb.eStateStopped, "Process should have been stopped.") + + target2 = self.dbg.CreateTarget(exe) + process2 = target2.LaunchSimple (None, None, self.get_process_working_directory()) + self.assertTrue(process2, PROCESS_IS_VALID) + + self.assertTrue(process2.GetState() == lldb.eStateExited, "Process should have exited.") + self.assertTrue(process2.GetExitStatus() == 0, + "Process returned non-zero status. Were incorrect file descriptors passed?") + if __name__ == '__main__': import atexit