From 86a5548585f345b6b24d88032d5f0e1914813bfb Mon Sep 17 00:00:00 2001 From: "Gregory P. Smith" Date: Mon, 4 Dec 2023 15:56:15 -0800 Subject: [PATCH 01/10] gh-112334: Regression test that vfork is used when expected. --- Lib/test/support/script_helper.py | 15 +++++ Lib/test/test_subprocess.py | 62 +++++++++++++++++++ ...-12-04-15-56-11.gh-issue-112334.FFc9Ti.rst | 2 + 3 files changed, 79 insertions(+) create mode 100644 Misc/NEWS.d/next/Tests/2023-12-04-15-56-11.gh-issue-112334.FFc9Ti.rst diff --git a/Lib/test/support/script_helper.py b/Lib/test/support/script_helper.py index 7dffe79a0da04e..ed4aa329990e60 100644 --- a/Lib/test/support/script_helper.py +++ b/Lib/test/support/script_helper.py @@ -92,13 +92,28 @@ def fail(self, cmd_line): # Executing the interpreter in a subprocess @support.requires_subprocess() def run_python_until_end(*args, **env_vars): + """Used to implement assert_python_*. + + *args are the command line flags to pass to the python interpreter. + **env_vars keyword arguments are environment variables to set on the process. + + If _run_using_command= is supplied, it must be a list of + command line arguments to prepend to the command line used. + Useful when you want to run another command that should launch the + python interpreter via its own arguments. ["/bin/echo", "--"] for + example could print the unquoted python command line instead of + run it. + """ env_required = interpreter_requires_environment() + run_using_command = env_vars.pop('_run_using_command', None) cwd = env_vars.pop('__cwd', None) if '__isolated' in env_vars: isolated = env_vars.pop('__isolated') else: isolated = not env_vars and not env_required cmd_line = [sys.executable, '-X', 'faulthandler'] + if run_using_command: + cmd_line = run_using_command + cmd_line if isolated: # isolated mode: ignore Python environment variables, ignore user # site-packages, and don't add the current directory to sys.path diff --git a/Lib/test/test_subprocess.py b/Lib/test/test_subprocess.py index 319bc0d2638563..0ee6043a383c9b 100644 --- a/Lib/test/test_subprocess.py +++ b/Lib/test/test_subprocess.py @@ -1570,12 +1570,74 @@ def test__use_vfork(self, mock_fork_exec): with self.assertRaises(RuntimeError): subprocess.run([sys.executable, "-c", "pass"]) mock_fork_exec.assert_called_once() + # NOTE: These assertions are *ugly* as they require the last arg + # to remain the have_vfork boolean. We really need to refactor away + # from the giant "wall of args" internal C extension API. self.assertTrue(mock_fork_exec.call_args.args[-1]) with mock.patch.object(subprocess, '_USE_VFORK', False): with self.assertRaises(RuntimeError): subprocess.run([sys.executable, "-c", "pass"]) self.assertFalse(mock_fork_exec.call_args_list[-1].args[-1]) + @unittest.skipIf(not sysconfig.get_config_var("HAVE_VFORK"), + "vfork() not enabled by configure.") + @unittest.skipIf(sys.platform != "linux", "Linux only, requires strace.") + def test_vfork_used_when_expected(self): + # This is a performance regression test to ensure we default to using + # vfork() when possible. + strace_binary = "/usr/bin/strace" + # The only system calls we are interested in. + strace_filter = "--trace=execve,clone,clone3,fork,vfork,exit,exit_group" + true_binary = "/bin/true" + strace_command = [strace_binary, strace_filter] + + does_strace_work_process = subprocess.run( + strace_command + [true_binary], + stderr=subprocess.PIPE, + stdout=subprocess.DEVNULL, + ) + if (does_strace_work_process.returncode != 0 or + b"+++ exited with 0 +++" not in does_strace_work_process.stderr): + self.skipTest("strace not found or is not working as expected.") + + with self.subTest(name="default_is_vfork"): + vfork_result = assert_python_ok( + "-c", + f"""if True: + import subprocess + subprocess.check_call([{true_binary!r}]) + """, + _run_using_command=strace_command, + ) + self.assertRegex(vfork_result.err, br"(?m)^vfork[(]") + self.assertNotRegex(vfork_result.err, br"(?m)^(fork|clone)") + + # Test that each individual thing that would disable the use of vfork + # actually disables it. + for sub_name, preamble, sp_kwarg, expect_permission_error in ( + ("!use_vfork", "subprocess._USE_VFORK = False", "", False), + ("preexec", "", "preexec_fn=lambda: None", False), + ("setgid", "", f"group={os.getgid()}", True), + ("setuid", "", f"user={os.getuid()}", True), + ("setgroups", "", "extra_groups=[]", True), + ): + with self.subTest(name=sub_name): + non_vfork_result = assert_python_ok( + "-c", + textwrap.dedent(f"""\ + import subprocess + {preamble} + try: + subprocess.check_call( + [{true_binary!r}], **dict({sp_kwarg})) + except PermissionError: + if not {expect_permission_error}: + raise"""), + _run_using_command=strace_command, + ) + self.assertNotRegex(non_vfork_result.err, br"(?m)^vfork[(]") + self.assertRegex(non_vfork_result.err, br"(?m)^(fork|clone)") + class RunFuncTestCase(BaseTestCase): def run_python(self, code, **kwargs): diff --git a/Misc/NEWS.d/next/Tests/2023-12-04-15-56-11.gh-issue-112334.FFc9Ti.rst b/Misc/NEWS.d/next/Tests/2023-12-04-15-56-11.gh-issue-112334.FFc9Ti.rst new file mode 100644 index 00000000000000..aeaad6e5055522 --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2023-12-04-15-56-11.gh-issue-112334.FFc9Ti.rst @@ -0,0 +1,2 @@ +Adds a regression test to verify that ``vfork()`` is used when expected by +:mod:`subprocess` on vfork enabled POSIX systems (Linux). From 2f9d3292b3176604fe7de1090da1e79929406ee5 Mon Sep 17 00:00:00 2001 From: "Gregory P. Smith" Date: Mon, 4 Dec 2023 20:31:01 -0800 Subject: [PATCH 02/10] Move the vfork tests to POSIXProcessTestCase. This way they only get run once instead of twice via NoPoll. --- Lib/test/test_subprocess.py | 154 ++++++++++++++++++------------------ 1 file changed, 77 insertions(+), 77 deletions(-) diff --git a/Lib/test/test_subprocess.py b/Lib/test/test_subprocess.py index 0ee6043a383c9b..f4f441e54fc6f0 100644 --- a/Lib/test/test_subprocess.py +++ b/Lib/test/test_subprocess.py @@ -1561,83 +1561,6 @@ def test_class_getitems(self): self.assertIsInstance(subprocess.Popen[bytes], types.GenericAlias) self.assertIsInstance(subprocess.CompletedProcess[str], types.GenericAlias) - @unittest.skipIf(not sysconfig.get_config_var("HAVE_VFORK"), - "vfork() not enabled by configure.") - @mock.patch("subprocess._fork_exec") - def test__use_vfork(self, mock_fork_exec): - self.assertTrue(subprocess._USE_VFORK) # The default value regardless. - mock_fork_exec.side_effect = RuntimeError("just testing args") - with self.assertRaises(RuntimeError): - subprocess.run([sys.executable, "-c", "pass"]) - mock_fork_exec.assert_called_once() - # NOTE: These assertions are *ugly* as they require the last arg - # to remain the have_vfork boolean. We really need to refactor away - # from the giant "wall of args" internal C extension API. - self.assertTrue(mock_fork_exec.call_args.args[-1]) - with mock.patch.object(subprocess, '_USE_VFORK', False): - with self.assertRaises(RuntimeError): - subprocess.run([sys.executable, "-c", "pass"]) - self.assertFalse(mock_fork_exec.call_args_list[-1].args[-1]) - - @unittest.skipIf(not sysconfig.get_config_var("HAVE_VFORK"), - "vfork() not enabled by configure.") - @unittest.skipIf(sys.platform != "linux", "Linux only, requires strace.") - def test_vfork_used_when_expected(self): - # This is a performance regression test to ensure we default to using - # vfork() when possible. - strace_binary = "/usr/bin/strace" - # The only system calls we are interested in. - strace_filter = "--trace=execve,clone,clone3,fork,vfork,exit,exit_group" - true_binary = "/bin/true" - strace_command = [strace_binary, strace_filter] - - does_strace_work_process = subprocess.run( - strace_command + [true_binary], - stderr=subprocess.PIPE, - stdout=subprocess.DEVNULL, - ) - if (does_strace_work_process.returncode != 0 or - b"+++ exited with 0 +++" not in does_strace_work_process.stderr): - self.skipTest("strace not found or is not working as expected.") - - with self.subTest(name="default_is_vfork"): - vfork_result = assert_python_ok( - "-c", - f"""if True: - import subprocess - subprocess.check_call([{true_binary!r}]) - """, - _run_using_command=strace_command, - ) - self.assertRegex(vfork_result.err, br"(?m)^vfork[(]") - self.assertNotRegex(vfork_result.err, br"(?m)^(fork|clone)") - - # Test that each individual thing that would disable the use of vfork - # actually disables it. - for sub_name, preamble, sp_kwarg, expect_permission_error in ( - ("!use_vfork", "subprocess._USE_VFORK = False", "", False), - ("preexec", "", "preexec_fn=lambda: None", False), - ("setgid", "", f"group={os.getgid()}", True), - ("setuid", "", f"user={os.getuid()}", True), - ("setgroups", "", "extra_groups=[]", True), - ): - with self.subTest(name=sub_name): - non_vfork_result = assert_python_ok( - "-c", - textwrap.dedent(f"""\ - import subprocess - {preamble} - try: - subprocess.check_call( - [{true_binary!r}], **dict({sp_kwarg})) - except PermissionError: - if not {expect_permission_error}: - raise"""), - _run_using_command=strace_command, - ) - self.assertNotRegex(non_vfork_result.err, br"(?m)^vfork[(]") - self.assertRegex(non_vfork_result.err, br"(?m)^(fork|clone)") - class RunFuncTestCase(BaseTestCase): def run_python(self, code, **kwargs): @@ -3422,6 +3345,83 @@ def exit_handler(): self.assertEqual(out, b'') self.assertIn(b"preexec_fn not supported at interpreter shutdown", err) + @unittest.skipIf(not sysconfig.get_config_var("HAVE_VFORK"), + "vfork() not enabled by configure.") + @mock.patch("subprocess._fork_exec") + def test__use_vfork(self, mock_fork_exec): + self.assertTrue(subprocess._USE_VFORK) # The default value regardless. + mock_fork_exec.side_effect = RuntimeError("just testing args") + with self.assertRaises(RuntimeError): + subprocess.run([sys.executable, "-c", "pass"]) + mock_fork_exec.assert_called_once() + # NOTE: These assertions are *ugly* as they require the last arg + # to remain the have_vfork boolean. We really need to refactor away + # from the giant "wall of args" internal C extension API. + self.assertTrue(mock_fork_exec.call_args.args[-1]) + with mock.patch.object(subprocess, '_USE_VFORK', False): + with self.assertRaises(RuntimeError): + subprocess.run([sys.executable, "-c", "pass"]) + self.assertFalse(mock_fork_exec.call_args_list[-1].args[-1]) + + @unittest.skipIf(not sysconfig.get_config_var("HAVE_VFORK"), + "vfork() not enabled by configure.") + @unittest.skipIf(sys.platform != "linux", "Linux only, requires strace.") + def test_vfork_used_when_expected(self): + # This is a performance regression test to ensure we default to using + # vfork() when possible. + strace_binary = "/usr/bin/strace" + # The only system calls we are interested in. + strace_filter = "--trace=execve,clone,clone3,fork,vfork,exit,exit_group" + true_binary = "/bin/true" + strace_command = [strace_binary, strace_filter] + + does_strace_work_process = subprocess.run( + strace_command + [true_binary], + stderr=subprocess.PIPE, + stdout=subprocess.DEVNULL, + ) + if (does_strace_work_process.returncode != 0 or + b"+++ exited with 0 +++" not in does_strace_work_process.stderr): + self.skipTest("strace not found or is not working as expected.") + + with self.subTest(name="default_is_vfork"): + vfork_result = assert_python_ok( + "-c", + f"""if True: + import subprocess + subprocess.check_call([{true_binary!r}]) + """, + _run_using_command=strace_command, + ) + self.assertRegex(vfork_result.err, br"(?m)^vfork[(]") + self.assertNotRegex(vfork_result.err, br"(?m)^(fork|clone)") + + # Test that each individual thing that would disable the use of vfork + # actually disables it. + for sub_name, preamble, sp_kwarg, expect_permission_error in ( + ("!use_vfork", "subprocess._USE_VFORK = False", "", False), + ("preexec", "", "preexec_fn=lambda: None", False), + ("setgid", "", f"group={os.getgid()}", True), + ("setuid", "", f"user={os.getuid()}", True), + ("setgroups", "", "extra_groups=[]", True), + ): + with self.subTest(name=sub_name): + non_vfork_result = assert_python_ok( + "-c", + textwrap.dedent(f"""\ + import subprocess + {preamble} + try: + subprocess.check_call( + [{true_binary!r}], **dict({sp_kwarg})) + except PermissionError: + if not {expect_permission_error}: + raise"""), + _run_using_command=strace_command, + ) + self.assertNotRegex(non_vfork_result.err, br"(?m)^vfork[(]") + self.assertRegex(non_vfork_result.err, br"(?m)^(fork|clone)") + @unittest.skipUnless(mswindows, "Windows specific tests") class Win32ProcessTestCase(BaseTestCase): From 947be7f9d6de76b62737841fb4bf31d4b4aefae0 Mon Sep 17 00:00:00 2001 From: "Gregory P. Smith" Date: Mon, 4 Dec 2023 20:34:00 -0800 Subject: [PATCH 03/10] Add strace to the Linux CI images. --- .github/workflows/posix-deps-apt.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/posix-deps-apt.sh b/.github/workflows/posix-deps-apt.sh index bbae378f7b994e..0800401f4cd113 100755 --- a/.github/workflows/posix-deps-apt.sh +++ b/.github/workflows/posix-deps-apt.sh @@ -21,6 +21,7 @@ apt-get -yq install \ libssl-dev \ lzma \ lzma-dev \ + strace \ tk-dev \ uuid-dev \ xvfb \ From 48e01eb783607ab1d41da4948caeb9bb14f1b334 Mon Sep 17 00:00:00 2001 From: "Gregory P. Smith" Date: Mon, 4 Dec 2023 21:11:11 -0800 Subject: [PATCH 04/10] fix the strace availability check. --- Lib/test/test_subprocess.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_subprocess.py b/Lib/test/test_subprocess.py index f4f441e54fc6f0..1675a73a5023c4 100644 --- a/Lib/test/test_subprocess.py +++ b/Lib/test/test_subprocess.py @@ -3375,6 +3375,8 @@ def test_vfork_used_when_expected(self): true_binary = "/bin/true" strace_command = [strace_binary, strace_filter] + if os.path.isfile(strace_binary): + self.skipTest(f"{strace_binary} not found.") does_strace_work_process = subprocess.run( strace_command + [true_binary], stderr=subprocess.PIPE, @@ -3382,7 +3384,7 @@ def test_vfork_used_when_expected(self): ) if (does_strace_work_process.returncode != 0 or b"+++ exited with 0 +++" not in does_strace_work_process.stderr): - self.skipTest("strace not found or is not working as expected.") + self.skipTest("strace is not working as expected.") with self.subTest(name="default_is_vfork"): vfork_result = assert_python_ok( From fef739875178960d8d5ffe49f0a22ede3a7556f4 Mon Sep 17 00:00:00 2001 From: "Gregory P. Smith" Date: Mon, 4 Dec 2023 21:26:27 -0800 Subject: [PATCH 05/10] "really" fix the strace detection. --- Lib/test/test_subprocess.py | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/Lib/test/test_subprocess.py b/Lib/test/test_subprocess.py index 1675a73a5023c4..07482832b1fffa 100644 --- a/Lib/test/test_subprocess.py +++ b/Lib/test/test_subprocess.py @@ -3375,16 +3375,19 @@ def test_vfork_used_when_expected(self): true_binary = "/bin/true" strace_command = [strace_binary, strace_filter] - if os.path.isfile(strace_binary): - self.skipTest(f"{strace_binary} not found.") - does_strace_work_process = subprocess.run( - strace_command + [true_binary], - stderr=subprocess.PIPE, - stdout=subprocess.DEVNULL, - ) - if (does_strace_work_process.returncode != 0 or - b"+++ exited with 0 +++" not in does_strace_work_process.stderr): - self.skipTest("strace is not working as expected.") + try: + does_strace_work_process = subprocess.run( + strace_command + [true_binary], + stderr=subprocess.PIPE, + stdout=subprocess.DEVNULL, + ) + rc = does_strace_work_process.returncode + stderr = does_strace_work_process.stderr + except OSError: + rc = -1 + stderr = "" + if rc or (b"+++ exited with 0 +++" not in stderr): + self.skipTest("strace not found or not working as expected.") with self.subTest(name="default_is_vfork"): vfork_result = assert_python_ok( From 91d7f9abf6fa97882efffa5f8a3f4a08b72aa532 Mon Sep 17 00:00:00 2001 From: "Gregory P. Smith" Date: Mon, 4 Dec 2023 21:32:08 -0800 Subject: [PATCH 06/10] consistent use of dedent --- Lib/test/test_subprocess.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_subprocess.py b/Lib/test/test_subprocess.py index 07482832b1fffa..e7cc71429fc6ea 100644 --- a/Lib/test/test_subprocess.py +++ b/Lib/test/test_subprocess.py @@ -3392,10 +3392,9 @@ def test_vfork_used_when_expected(self): with self.subTest(name="default_is_vfork"): vfork_result = assert_python_ok( "-c", - f"""if True: + textwrap.dedent(f"""\ import subprocess - subprocess.check_call([{true_binary!r}]) - """, + subprocess.check_call([{true_binary!r}])"""), _run_using_command=strace_command, ) self.assertRegex(vfork_result.err, br"(?m)^vfork[(]") From 68cc668d355291ab6644a03ce06522e5baffa6d4 Mon Sep 17 00:00:00 2001 From: "Gregory P. Smith" Date: Tue, 5 Dec 2023 00:45:53 -0800 Subject: [PATCH 07/10] Loosen the test, different architectures use different syscall variants. --- Lib/test/test_subprocess.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/Lib/test/test_subprocess.py b/Lib/test/test_subprocess.py index e7cc71429fc6ea..3d6cd1b4ecab76 100644 --- a/Lib/test/test_subprocess.py +++ b/Lib/test/test_subprocess.py @@ -3397,8 +3397,10 @@ def test_vfork_used_when_expected(self): subprocess.check_call([{true_binary!r}])"""), _run_using_command=strace_command, ) - self.assertRegex(vfork_result.err, br"(?m)^vfork[(]") - self.assertNotRegex(vfork_result.err, br"(?m)^(fork|clone)") + # Match both vfork() and clone(..., flags=...|CLONE_VFORK|...) + self.assertRegex(vfork_result.err, br"(?mi)^vfork") + # Do NOT check that fork() or other clones did not happen. + # If the OS denys the vfork it'll fallback to plain fork(). # Test that each individual thing that would disable the use of vfork # actually disables it. @@ -3423,8 +3425,8 @@ def test_vfork_used_when_expected(self): raise"""), _run_using_command=strace_command, ) - self.assertNotRegex(non_vfork_result.err, br"(?m)^vfork[(]") - self.assertRegex(non_vfork_result.err, br"(?m)^(fork|clone)") + # Ensure neither vfork() or clone(..., flags=...|CLONE_VFORK|...). + self.assertNotRegex(non_vfork_result.err, br"(?mi)^vfork") @unittest.skipUnless(mswindows, "Windows specific tests") From a737bd3037f0dc52c988f71ec223f70bc6c5f22f Mon Sep 17 00:00:00 2001 From: "Gregory P. Smith" Date: Tue, 5 Dec 2023 12:57:12 -0800 Subject: [PATCH 08/10] non-late-night regex fixing. --- Lib/test/test_subprocess.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_subprocess.py b/Lib/test/test_subprocess.py index 3d6cd1b4ecab76..ff5571dfa5ab92 100644 --- a/Lib/test/test_subprocess.py +++ b/Lib/test/test_subprocess.py @@ -3398,7 +3398,7 @@ def test_vfork_used_when_expected(self): _run_using_command=strace_command, ) # Match both vfork() and clone(..., flags=...|CLONE_VFORK|...) - self.assertRegex(vfork_result.err, br"(?mi)^vfork") + self.assertRegex(vfork_result.err, br"(?mi)vfork") # Do NOT check that fork() or other clones did not happen. # If the OS denys the vfork it'll fallback to plain fork(). @@ -3426,7 +3426,7 @@ def test_vfork_used_when_expected(self): _run_using_command=strace_command, ) # Ensure neither vfork() or clone(..., flags=...|CLONE_VFORK|...). - self.assertNotRegex(non_vfork_result.err, br"(?mi)^vfork") + self.assertNotRegex(non_vfork_result.err, br"(?mi)vfork") @unittest.skipUnless(mswindows, "Windows specific tests") From d57ee334a30c78ab70df685bf51750f6d6edff15 Mon Sep 17 00:00:00 2001 From: "Gregory P. Smith [Google LLC]" Date: Fri, 8 Dec 2023 15:57:53 -0800 Subject: [PATCH 09/10] Address code review comments. --- Lib/test/support/script_helper.py | 4 ++-- Lib/test/test_subprocess.py | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Lib/test/support/script_helper.py b/Lib/test/support/script_helper.py index ed4aa329990e60..759020c33aa700 100644 --- a/Lib/test/support/script_helper.py +++ b/Lib/test/support/script_helper.py @@ -97,7 +97,7 @@ def run_python_until_end(*args, **env_vars): *args are the command line flags to pass to the python interpreter. **env_vars keyword arguments are environment variables to set on the process. - If _run_using_command= is supplied, it must be a list of + If __run_using_command= is supplied, it must be a list of command line arguments to prepend to the command line used. Useful when you want to run another command that should launch the python interpreter via its own arguments. ["/bin/echo", "--"] for @@ -105,7 +105,7 @@ def run_python_until_end(*args, **env_vars): run it. """ env_required = interpreter_requires_environment() - run_using_command = env_vars.pop('_run_using_command', None) + run_using_command = env_vars.pop('__run_using_command', None) cwd = env_vars.pop('__cwd', None) if '__isolated' in env_vars: isolated = env_vars.pop('__isolated') diff --git a/Lib/test/test_subprocess.py b/Lib/test/test_subprocess.py index ff5571dfa5ab92..7f3bbfa9cd99c6 100644 --- a/Lib/test/test_subprocess.py +++ b/Lib/test/test_subprocess.py @@ -3395,10 +3395,10 @@ def test_vfork_used_when_expected(self): textwrap.dedent(f"""\ import subprocess subprocess.check_call([{true_binary!r}])"""), - _run_using_command=strace_command, + __run_using_command=strace_command, ) # Match both vfork() and clone(..., flags=...|CLONE_VFORK|...) - self.assertRegex(vfork_result.err, br"(?mi)vfork") + self.assertRegex(vfork_result.err, br"(?i)vfork") # Do NOT check that fork() or other clones did not happen. # If the OS denys the vfork it'll fallback to plain fork(). @@ -3423,10 +3423,10 @@ def test_vfork_used_when_expected(self): except PermissionError: if not {expect_permission_error}: raise"""), - _run_using_command=strace_command, + __run_using_command=strace_command, ) # Ensure neither vfork() or clone(..., flags=...|CLONE_VFORK|...). - self.assertNotRegex(non_vfork_result.err, br"(?mi)vfork") + self.assertNotRegex(non_vfork_result.err, br"(?i)vfork") @unittest.skipUnless(mswindows, "Windows specific tests") From c55fafc70e0489b9e9d016b3924f42aa7b85f0ab Mon Sep 17 00:00:00 2001 From: "Gregory P. Smith [Google LLC]" Date: Fri, 8 Dec 2023 16:00:51 -0800 Subject: [PATCH 10/10] simplify the syscalls strace reports. This makes output easier to understand if debugging a failure. (removes execve which shows up for the initial process launch by strace on _some_ platforms, adds clone2 which claims to only be used on an obsolete architecture but if it cropped up again for some future reason would be annoying to have break the test) --- Lib/test/test_subprocess.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_subprocess.py b/Lib/test/test_subprocess.py index 7f3bbfa9cd99c6..5eeea54fd55f1a 100644 --- a/Lib/test/test_subprocess.py +++ b/Lib/test/test_subprocess.py @@ -3371,7 +3371,7 @@ def test_vfork_used_when_expected(self): # vfork() when possible. strace_binary = "/usr/bin/strace" # The only system calls we are interested in. - strace_filter = "--trace=execve,clone,clone3,fork,vfork,exit,exit_group" + strace_filter = "--trace=clone,clone2,clone3,fork,vfork,exit,exit_group" true_binary = "/bin/true" strace_command = [strace_binary, strace_filter]