1"""
2Test whether a process started by lldb has no extra file descriptors open.
3"""
4
5
6
7import lldb
8from lldbsuite.test import lldbutil
9from lldbsuite.test.lldbtest import *
10from lldbsuite.test.decorators import *
11
12
13def python_leaky_fd_version(test):
14    import sys
15    # Python random module leaks file descriptors on some versions.
16    if sys.version_info >= (2, 7, 8) and sys.version_info < (2, 7, 10):
17        return "Python random module leaks file descriptors in this python version"
18    return None
19
20
21class AvoidsFdLeakTestCase(TestBase):
22
23    NO_DEBUG_INFO_TESTCASE = True
24
25    mydir = TestBase.compute_mydir(__file__)
26
27    @expectedFailureIfFn(python_leaky_fd_version, "bugs.freebsd.org/197376")
28    @expectedFailureAll(
29        oslist=['freebsd'],
30        bugnumber="llvm.org/pr25624 still failing with Python 2.7.10")
31    # The check for descriptor leakage needs to be implemented differently
32    # here.
33    @skipIfWindows
34    @skipIfTargetAndroid()  # Android have some other file descriptors open by the shell
35    @skipIfDarwinEmbedded # <rdar://problem/33888742>  # debugserver on ios has an extra fd open on launch
36    def test_fd_leak_basic(self):
37        self.do_test([])
38
39    @expectedFailureIfFn(python_leaky_fd_version, "bugs.freebsd.org/197376")
40    @expectedFailureAll(
41        oslist=['freebsd'],
42        bugnumber="llvm.org/pr25624 still failing with Python 2.7.10")
43    # The check for descriptor leakage needs to be implemented differently
44    # here.
45    @skipIfWindows
46    @skipIfTargetAndroid()  # Android have some other file descriptors open by the shell
47    @skipIfDarwinEmbedded # <rdar://problem/33888742>  # debugserver on ios has an extra fd open on launch
48    def test_fd_leak_log(self):
49        self.do_test(["log enable -f '/dev/null' lldb commands"])
50
51    def do_test(self, commands):
52        self.build()
53        exe = self.getBuildArtifact("a.out")
54
55        for c in commands:
56            self.runCmd(c)
57
58        target = self.dbg.CreateTarget(exe)
59
60        process = target.LaunchSimple(
61            None, None, self.get_process_working_directory())
62        self.assertTrue(process, PROCESS_IS_VALID)
63
64        self.assertTrue(
65            process.GetState() == lldb.eStateExited,
66            "Process should have exited.")
67        self.assertTrue(
68            process.GetExitStatus() == 0,
69            "Process returned non-zero status. Were incorrect file descriptors passed?")
70
71    @expectedFailureIfFn(python_leaky_fd_version, "bugs.freebsd.org/197376")
72    @expectedFailureAll(
73        oslist=['freebsd'],
74        bugnumber="llvm.org/pr25624 still failing with Python 2.7.10")
75    # The check for descriptor leakage needs to be implemented differently
76    # here.
77    @skipIfWindows
78    @skipIfTargetAndroid()  # Android have some other file descriptors open by the shell
79    @skipIfDarwinEmbedded # <rdar://problem/33888742>  # debugserver on ios has an extra fd open on launch
80    def test_fd_leak_multitarget(self):
81        self.build()
82        exe = self.getBuildArtifact("a.out")
83
84        target = self.dbg.CreateTarget(exe)
85        breakpoint = target.BreakpointCreateBySourceRegex(
86            'Set breakpoint here', lldb.SBFileSpec("main.c", False))
87        self.assertTrue(breakpoint, VALID_BREAKPOINT)
88
89        process1 = target.LaunchSimple(
90            None, None, self.get_process_working_directory())
91        self.assertTrue(process1, PROCESS_IS_VALID)
92        self.assertTrue(
93            process1.GetState() == lldb.eStateStopped,
94            "Process should have been stopped.")
95
96        target2 = self.dbg.CreateTarget(exe)
97        process2 = target2.LaunchSimple(
98            None, None, self.get_process_working_directory())
99        self.assertTrue(process2, PROCESS_IS_VALID)
100
101        self.assertTrue(
102            process2.GetState() == lldb.eStateExited,
103            "Process should have exited.")
104        self.assertTrue(
105            process2.GetExitStatus() == 0,
106            "Process returned non-zero status. Were incorrect file descriptors passed?")
107