@@ -241,10 +241,10 @@ def __init__(
241241 # we need to ensure that they can read and write to the directory.
242242 # But we don't want everybody on the system to, which is why the
243243 # outer directory exists with no read permissions.
244- self ._outer_dir = tempfile .mkdtemp (
244+ self ._outer_dir : str = tempfile .mkdtemp (
245245 dir = self .temp_dir , prefix = "cms-%s-" % (self .name )
246246 )
247- self ._home = os .path .join (self ._outer_dir , "home" )
247+ self ._home : str = os .path .join (self ._outer_dir , "home" )
248248 self ._home_dest = "/tmp"
249249 os .mkdir (self ._home )
250250
@@ -266,15 +266,16 @@ def __init__(
266266 self .inherit_env : list [str ] = [] # -E
267267 self .set_env : dict [str , str ] = {} # -E
268268 self .fsize : int | None = None # -f
269- self .stdin_file : str | None = None # -i
270- self .stdout_file : str | None = None # -o
271- self .stderr_file : str | None = None # -r
269+ self .stdin_file : str | int | None = None # -i
270+ self .stdout_file : str | int | None = None # -o
271+ self .stderr_file : str | int | None = None # -r
272272 self .stack_space : int | None = None # -k
273273 self .address_space : int | None = None # -m
274274 self .timeout : float | None = None # -t
275275 self .verbosity : int = 0 # -v
276276 self .wallclock_timeout : float | None = None # -w
277277 self .extra_timeout : float | None = None # -x
278+ self .close_fds = True
278279
279280 self .max_processes : int = 1
280281
@@ -656,13 +657,15 @@ def execute_without_std(
656657 return the Popen object from subprocess.
657658
658659 """
659- popen = self ._popen (
660- command ,
661- stdin = subprocess .PIPE ,
662- stdout = subprocess .PIPE ,
663- stderr = subprocess .PIPE ,
664- close_fds = True ,
660+ stdin = self .stdin_file if isinstance (self .stdin_file , int ) else subprocess .PIPE
661+ stdout = (
662+ self .stdout_file if isinstance (self .stdout_file , int ) else subprocess .PIPE
665663 )
664+ stderr = (
665+ self .stderr_file if isinstance (self .stderr_file , int ) else subprocess .PIPE
666+ )
667+
668+ popen = self ._popen (command , stdin = stdin , stdout = stdout , stderr = stderr )
666669
667670 # If the caller wants us to wait for completion, we also avoid
668671 # std*** to interfere with command. Otherwise we let the
@@ -730,12 +733,13 @@ def cleanup(self, delete: bool = False):
730733 self ._home_dest ,
731734 ],
732735 stdout = subprocess .DEVNULL ,
733- stderr = subprocess .STDOUT ,
736+ stderr = subprocess .DEVNULL ,
734737 )
735738
736739 # Tell isolate to cleanup the sandbox.
737740 subprocess .check_call (
738- exe + ["--cleanup" ], stdout = subprocess .DEVNULL , stderr = subprocess .STDOUT
741+ exe + ["--cleanup" ],
742+ stdout = subprocess .DEVNULL ,
739743 )
740744
741745 if delete :
@@ -877,21 +881,21 @@ def build_box_options(self) -> list[str]:
877881 if self .fsize is not None :
878882 # Isolate wants file size as KiB.
879883 res += ["--fsize=%d" % (self .fsize // 1024 )]
880- if self .stdin_file is not None :
884+ if isinstance ( self .stdin_file , str ) :
881885 res += ["--stdin=%s" % self .inner_absolute_path (self .stdin_file )]
882886 if self .stack_space is not None :
883887 # Isolate wants stack size as KiB.
884888 res += ["--stack=%d" % (self .stack_space // 1024 )]
885889 if self .address_space is not None :
886890 # Isolate wants memory size as KiB.
887891 res += ["--cg-mem=%d" % (self .address_space // 1024 )]
888- if self .stdout_file is not None :
892+ if isinstance ( self .stdout_file , str ) :
889893 res += ["--stdout=%s" % self .inner_absolute_path (self .stdout_file )]
890894 if self .max_processes is not None :
891895 res += ["--processes=%d" % self .max_processes ]
892896 else :
893897 res += ["--processes" ]
894- if self .stderr_file is not None :
898+ if isinstance ( self .stderr_file , str ) :
895899 res += ["--stderr=%s" % self .inner_absolute_path (self .stderr_file )]
896900 if self .timeout is not None :
897901 res += ["--time=%g" % self .timeout ]
@@ -900,6 +904,8 @@ def build_box_options(self) -> list[str]:
900904 res += ["--wall-time=%g" % self .wallclock_timeout ]
901905 if self .extra_timeout is not None :
902906 res += ["--extra-time=%g" % self .extra_timeout ]
907+ if not self .close_fds :
908+ res += ["--inherit-fds" , "--open-files=0" ]
903909 res += ["--meta=%s" % ("%s.%d" % (self .info_basename , self .exec_num ))]
904910 res += ["--run" ]
905911 return res
@@ -957,7 +963,6 @@ def _popen(
957963 stdin : int | None = None ,
958964 stdout : int | None = None ,
959965 stderr : int | None = None ,
960- close_fds : bool = True ,
961966 ) -> subprocess .Popen :
962967 """Execute the given command in the sandbox using
963968 subprocess.Popen, assigning the corresponding standard file
@@ -967,7 +972,6 @@ def _popen(
967972 stdin: a file descriptor.
968973 stdout: a file descriptor.
969974 stderr: a file descriptor.
970- close_fds: close all file descriptor before executing.
971975
972976 return: popen object.
973977
@@ -988,7 +992,11 @@ def _popen(
988992 os .chmod (self ._home , prev_permissions )
989993 try :
990994 p = subprocess .Popen (
991- args , stdin = stdin , stdout = stdout , stderr = stderr , close_fds = close_fds
995+ args ,
996+ stdin = stdin ,
997+ stdout = stdout ,
998+ stderr = stderr ,
999+ close_fds = self .close_fds ,
9921000 )
9931001 except OSError :
9941002 logger .critical (
@@ -1004,6 +1012,6 @@ def initialize_isolate(self):
10041012 """Initialize isolate's box."""
10051013 init_cmd = ["isolate" , "--box-id=%d" % self .box_id , "--cg" , "--init" ]
10061014 try :
1007- subprocess .check_call (init_cmd )
1015+ subprocess .check_call (init_cmd , stdout = subprocess . DEVNULL )
10081016 except subprocess .CalledProcessError as e :
10091017 raise SandboxInterfaceException ("Failed to initialize sandbox" ) from e
0 commit comments