@@ -244,10 +244,10 @@ def __init__(
244244 # we need to ensure that they can read and write to the directory.
245245 # But we don't want everybody on the system to, which is why the
246246 # outer directory exists with no read permissions.
247- self ._outer_dir = tempfile .mkdtemp (
247+ self ._outer_dir : str = tempfile .mkdtemp (
248248 dir = self .temp_dir , prefix = "cms-%s-" % (self .name )
249249 )
250- self ._home = os .path .join (self ._outer_dir , "home" )
250+ self ._home : str = os .path .join (self ._outer_dir , "home" )
251251 self ._home_dest = "/tmp"
252252 os .mkdir (self ._home )
253253
@@ -269,15 +269,16 @@ def __init__(
269269 self .inherit_env : list [str ] = [] # -E
270270 self .set_env : dict [str , str ] = {} # -E
271271 self .fsize : int | None = None # -f
272- self .stdin_file : str | None = None # -i
273- self .stdout_file : str | None = None # -o
274- self .stderr_file : str | None = None # -r
272+ self .stdin_file : str | int | None = None # -i
273+ self .stdout_file : str | int | None = None # -o
274+ self .stderr_file : str | int | None = None # -r
275275 self .stack_space : int | None = None # -k
276276 self .address_space : int | None = None # -m
277277 self .timeout : float | None = None # -t
278278 self .verbosity : int = 0 # -v
279279 self .wallclock_timeout : float | None = None # -w
280280 self .extra_timeout : float | None = None # -x
281+ self .close_fds = True
281282
282283 self .max_processes : int = 1
283284
@@ -655,13 +656,15 @@ def execute_without_std(
655656 return the Popen object from subprocess.
656657
657658 """
658- popen = self ._popen (
659- command ,
660- stdin = subprocess .PIPE ,
661- stdout = subprocess .PIPE ,
662- stderr = subprocess .PIPE ,
663- close_fds = True ,
659+ stdin = self .stdin_file if isinstance (self .stdin_file , int ) else subprocess .PIPE
660+ stdout = (
661+ self .stdout_file if isinstance (self .stdout_file , int ) else subprocess .PIPE
664662 )
663+ stderr = (
664+ self .stderr_file if isinstance (self .stderr_file , int ) else subprocess .PIPE
665+ )
666+
667+ popen = self ._popen (command , stdin = stdin , stdout = stdout , stderr = stderr )
665668
666669 # If the caller wants us to wait for completion, we also avoid
667670 # std*** to interfere with command. Otherwise we let the
@@ -729,12 +732,13 @@ def cleanup(self, delete: bool = False):
729732 self ._home_dest ,
730733 ],
731734 stdout = subprocess .DEVNULL ,
732- stderr = subprocess .STDOUT ,
735+ stderr = subprocess .DEVNULL ,
733736 )
734737
735738 # Tell isolate to cleanup the sandbox.
736739 subprocess .check_call (
737- exe + ["--cleanup" ], stdout = subprocess .DEVNULL , stderr = subprocess .STDOUT
740+ exe + ["--cleanup" ],
741+ stdout = subprocess .DEVNULL ,
738742 )
739743
740744 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