44from test .support import check_sanitizer
55from test .support import import_helper
66from test .support import os_helper
7- from test .support import strace_helper
87from test .support import warnings_helper
98from test .support .script_helper import assert_python_ok
109import subprocess
@@ -3416,33 +3415,44 @@ def __del__(self):
34163415
34173416 @unittest .skipIf (not sysconfig .get_config_var ("HAVE_VFORK" ),
34183417 "vfork() not enabled by configure." )
3419- @strace_helper . requires_strace ( )
3418+ @unittest . skipIf ( sys . platform != "linux" , "Linux only, requires strace." )
34203419 @mock .patch ("subprocess._USE_POSIX_SPAWN" , new = False )
34213420 def test_vfork_used_when_expected (self ):
34223421 # This is a performance regression test to ensure we default to using
34233422 # vfork() when possible.
34243423 # Technically this test could pass when posix_spawn is used as well
34253424 # because libc tends to implement that internally using vfork. But
34263425 # that'd just be testing a libc+kernel implementation detail.
3427-
3428- # Are intersted in the system calls:
3429- # clone,clone2,clone3,fork,vfork,exit,exit_group
3430- # Unfortunately using `--trace` with that list to strace fails because
3431- # not all are supported on all platforms (ex. clone2 is ia64 only...)
3432- # So instead use `%process` which is recommended by strace, and contains
3433- # the above.
3426+ strace_binary = "/usr/bin/strace"
3427+ # The only system calls we are interested in.
3428+ strace_filter = "--trace=clone,clone2,clone3,fork,vfork,exit,exit_group"
34343429 true_binary = "/bin/true"
3435- strace_args = ["--trace=%process" ]
3430+ strace_command = [strace_binary , strace_filter ]
3431+
3432+ try :
3433+ does_strace_work_process = subprocess .run (
3434+ strace_command + [true_binary ],
3435+ stderr = subprocess .PIPE ,
3436+ stdout = subprocess .DEVNULL ,
3437+ )
3438+ rc = does_strace_work_process .returncode
3439+ stderr = does_strace_work_process .stderr
3440+ except OSError :
3441+ rc = - 1
3442+ stderr = ""
3443+ if rc or (b"+++ exited with 0 +++" not in stderr ):
3444+ self .skipTest ("strace not found or not working as expected." )
34363445
34373446 with self .subTest (name = "default_is_vfork" ):
3438- vfork_result = strace_helper .strace_python (
3439- f"""\
3440- import subprocess
3441- subprocess.check_call([{ true_binary !r} ])""" ,
3442- strace_args
3447+ vfork_result = assert_python_ok (
3448+ "-c" ,
3449+ textwrap .dedent (f"""\
3450+ import subprocess
3451+ subprocess.check_call([{ true_binary !r} ])""" ),
3452+ __run_using_command = strace_command ,
34433453 )
34443454 # Match both vfork() and clone(..., flags=...|CLONE_VFORK|...)
3445- self .assertRegex (vfork_result .event_bytes , br"(?i)vfork" )
3455+ self .assertRegex (vfork_result .err , br"(?i)vfork" )
34463456 # Do NOT check that fork() or other clones did not happen.
34473457 # If the OS denys the vfork it'll fallback to plain fork().
34483458
@@ -3455,20 +3465,21 @@ def test_vfork_used_when_expected(self):
34553465 ("setgroups" , "" , "extra_groups=[]" , True ),
34563466 ):
34573467 with self .subTest (name = sub_name ):
3458- non_vfork_result = strace_helper .strace_python (
3459- f"""\
3468+ non_vfork_result = assert_python_ok (
3469+ "-c" ,
3470+ textwrap .dedent (f"""\
34603471 import subprocess
34613472 { preamble }
34623473 try:
34633474 subprocess.check_call(
34643475 [{ true_binary !r} ], **dict({ sp_kwarg } ))
34653476 except PermissionError:
34663477 if not { expect_permission_error } :
3467- raise""" ,
3468- strace_args
3478+ raise""" ) ,
3479+ __run_using_command = strace_command ,
34693480 )
34703481 # Ensure neither vfork() or clone(..., flags=...|CLONE_VFORK|...).
3471- self .assertNotRegex (non_vfork_result .event_bytes , br"(?i)vfork" )
3482+ self .assertNotRegex (non_vfork_result .err , br"(?i)vfork" )
34723483
34733484
34743485@unittest .skipUnless (mswindows , "Windows specific tests" )
0 commit comments