@@ -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 :
@@ -878,21 +882,21 @@ def build_box_options(self) -> list[str]:
878882 if self .fsize is not None :
879883 # Isolate wants file size as KiB.
880884 res += ["--fsize=%d" % (self .fsize // 1024 )]
881- if self .stdin_file is not None :
885+ if isinstance ( self .stdin_file , str ) :
882886 res += ["--stdin=%s" % self .inner_absolute_path (self .stdin_file )]
883887 if self .stack_space is not None :
884888 # Isolate wants stack size as KiB.
885889 res += ["--stack=%d" % (self .stack_space // 1024 )]
886890 if self .address_space is not None :
887891 # Isolate wants memory size as KiB.
888892 res += ["--cg-mem=%d" % (self .address_space // 1024 )]
889- if self .stdout_file is not None :
893+ if isinstance ( self .stdout_file , str ) :
890894 res += ["--stdout=%s" % self .inner_absolute_path (self .stdout_file )]
891895 if self .max_processes is not None :
892896 res += ["--processes=%d" % self .max_processes ]
893897 else :
894898 res += ["--processes" ]
895- if self .stderr_file is not None :
899+ if isinstance ( self .stderr_file , str ) :
896900 res += ["--stderr=%s" % self .inner_absolute_path (self .stderr_file )]
897901 if self .timeout is not None :
898902 res += ["--time=%g" % self .timeout ]
@@ -901,6 +905,8 @@ def build_box_options(self) -> list[str]:
901905 res += ["--wall-time=%g" % self .wallclock_timeout ]
902906 if self .extra_timeout is not None :
903907 res += ["--extra-time=%g" % self .extra_timeout ]
908+ if not self .close_fds :
909+ res += ["--inherit-fds" , "--open-files=0" ]
904910 res += ["--meta=%s" % ("%s.%d" % (self .info_basename , self .exec_num ))]
905911 res += ["--run" ]
906912 return res
@@ -958,7 +964,6 @@ def _popen(
958964 stdin : int | None = None ,
959965 stdout : int | None = None ,
960966 stderr : int | None = None ,
961- close_fds : bool = True ,
962967 ) -> subprocess .Popen :
963968 """Execute the given command in the sandbox using
964969 subprocess.Popen, assigning the corresponding standard file
@@ -968,7 +973,6 @@ def _popen(
968973 stdin: a file descriptor.
969974 stdout: a file descriptor.
970975 stderr: a file descriptor.
971- close_fds: close all file descriptor before executing.
972976
973977 return: popen object.
974978
@@ -989,7 +993,11 @@ def _popen(
989993 os .chmod (self ._home , prev_permissions )
990994 try :
991995 p = subprocess .Popen (
992- args , stdin = stdin , stdout = stdout , stderr = stderr , close_fds = close_fds
996+ args ,
997+ stdin = stdin ,
998+ stdout = stdout ,
999+ stderr = stderr ,
1000+ close_fds = self .close_fds ,
9931001 )
9941002 except OSError :
9951003 logger .critical (
@@ -1005,6 +1013,6 @@ def initialize_isolate(self):
10051013 """Initialize isolate's box."""
10061014 init_cmd = ["isolate" , "--box-id=%d" % self .box_id , "--cg" , "--init" ]
10071015 try :
1008- subprocess .check_call (init_cmd )
1016+ subprocess .check_call (init_cmd , stdout = subprocess . DEVNULL )
10091017 except subprocess .CalledProcessError as e :
10101018 raise SandboxInterfaceException ("Failed to initialize sandbox" ) from e
0 commit comments