xref: /llvm-project/lldb/test/API/functionalities/fork/concurrent_vfork/TestConcurrentVFork.py (revision 706821ba8ff9db829252581dd12d8c5ee2e7b3f0)
1"""
2Make sure that the concurrent vfork() from multiple threads works correctly.
3"""
4
5import lldb
6import lldbsuite.test.lldbutil as lldbutil
7from lldbsuite.test.lldbtest import *
8from lldbsuite.test.decorators import *
9
10
11class TestConcurrentVFork(TestBase):
12    NO_DEBUG_INFO_TESTCASE = True
13
14    def build_run_to_breakpoint(self, use_fork, call_exec):
15        self.build()
16
17        args = []
18        if use_fork:
19            args.append("--fork")
20        if call_exec:
21            args.append("--exec")
22        launch_info = lldb.SBLaunchInfo(args)
23        launch_info.SetWorkingDirectory(self.getBuildDir())
24
25        return lldbutil.run_to_source_breakpoint(
26            self, "// break here", lldb.SBFileSpec("main.cpp")
27        )
28
29    def follow_parent_helper(self, use_fork, call_exec):
30        (target, process, thread, bkpt) = self.build_run_to_breakpoint(
31            use_fork, call_exec
32        )
33
34        parent_pid = target.FindFirstGlobalVariable("g_pid").GetValueAsUnsigned()
35        self.runCmd("settings set target.process.follow-fork-mode parent")
36        self.runCmd("settings set target.process.stop-on-exec False", check=False)
37        self.expect(
38            "continue", substrs=[f"Process {parent_pid} exited with status = 0"]
39        )
40
41    def follow_child_helper(self, use_fork, call_exec):
42        self.build_run_to_breakpoint(use_fork, call_exec)
43
44        self.runCmd("settings set target.process.follow-fork-mode child")
45        self.runCmd("settings set target.process.stop-on-exec False", check=False)
46        # Child process exits with code "index + 10" since index is [0-4]
47        # so the exit code should be 1[0-4]
48        self.expect("continue", patterns=[r"exited with status = 1[0-4]"])
49
50    @skipUnlessPlatform(["linux"])
51    # https://github.com/llvm/llvm-project/issues/85084.
52    @skipIf(oslist=["linux"])
53    def test_follow_parent_vfork_no_exec(self):
54        """
55        Make sure that debugging concurrent vfork() from multiple threads won't crash lldb during follow-parent.
56        And follow-parent successfully detach all child processes and exit debugger without calling exec.
57        """
58        self.follow_parent_helper(use_fork=False, call_exec=False)
59
60    @skipUnlessPlatform(["linux"])
61    # https://github.com/llvm/llvm-project/issues/85084.
62    @skipIf(oslist=["linux"])
63    def test_follow_parent_fork_no_exec(self):
64        """
65        Make sure that debugging concurrent fork() from multiple threads won't crash lldb during follow-parent.
66        And follow-parent successfully detach all child processes and exit debugger without calling exec
67        """
68        self.follow_parent_helper(use_fork=True, call_exec=False)
69
70    @skipUnlessPlatform(["linux"])
71    # https://github.com/llvm/llvm-project/issues/85084.
72    @skipIf(oslist=["linux"])
73    def test_follow_parent_vfork_call_exec(self):
74        """
75        Make sure that debugging concurrent vfork() from multiple threads won't crash lldb during follow-parent.
76        And follow-parent successfully detach all child processes and exit debugger after calling exec.
77        """
78        self.follow_parent_helper(use_fork=False, call_exec=True)
79
80    @skipUnlessPlatform(["linux"])
81    # https://github.com/llvm/llvm-project/issues/85084.
82    @skipIf(oslist=["linux"])
83    def test_follow_parent_fork_call_exec(self):
84        """
85        Make sure that debugging concurrent vfork() from multiple threads won't crash lldb during follow-parent.
86        And follow-parent successfully detach all child processes and exit debugger after calling exec.
87        """
88        self.follow_parent_helper(use_fork=True, call_exec=True)
89
90    @skipUnlessPlatform(["linux"])
91    # https://github.com/llvm/llvm-project/issues/85084.
92    @skipIf(oslist=["linux"])
93    def test_follow_child_vfork_no_exec(self):
94        """
95        Make sure that debugging concurrent vfork() from multiple threads won't crash lldb during follow-child.
96        And follow-child successfully detach parent process and exit child process with correct exit code without calling exec.
97        """
98        self.follow_child_helper(use_fork=False, call_exec=False)
99
100    @skipUnlessPlatform(["linux"])
101    # https://github.com/llvm/llvm-project/issues/85084.
102    @skipIf(oslist=["linux"])
103    def test_follow_child_fork_no_exec(self):
104        """
105        Make sure that debugging concurrent fork() from multiple threads won't crash lldb during follow-child.
106        And follow-child successfully detach parent process and exit child process with correct exit code without calling exec.
107        """
108        self.follow_child_helper(use_fork=True, call_exec=False)
109
110    @skipUnlessPlatform(["linux"])
111    # https://github.com/llvm/llvm-project/issues/85084.
112    @skipIf(oslist=["linux"])
113    def test_follow_child_vfork_call_exec(self):
114        """
115        Make sure that debugging concurrent vfork() from multiple threads won't crash lldb during follow-child.
116        And follow-child successfully detach parent process and exit child process with correct exit code after calling exec.
117        """
118        self.follow_child_helper(use_fork=False, call_exec=True)
119
120    @skipUnlessPlatform(["linux"])
121    # https://github.com/llvm/llvm-project/issues/85084.
122    @skipIf(oslist=["linux"])
123    def test_follow_child_fork_call_exec(self):
124        """
125        Make sure that debugging concurrent fork() from multiple threads won't crash lldb during follow-child.
126        And follow-child successfully detach parent process and exit child process with correct exit code after calling exec.
127        """
128        self.follow_child_helper(use_fork=True, call_exec=True)
129