@@ -292,3 +292,50 @@ def test_stdin_blocking(self):
292292 finally :
293293 proc .stdout .close ()
294294 proc .stderr .close ()
295+
296+ def test_eof_too_early (self ):
297+ """The boot command should write an ECO marker to stdout, read the
298+ preamble from stdin, then execute it.
299+
300+ This test writes some data to STDIN and closes it then to create an
301+ EOF situation.
302+ 1. Fork child tries to read from STDIN, but stops as EOF is received.
303+ 2. Fork child crashes (trying to decompress the junk data)
304+ 3. Fork child's file descriptors (write pipes) are closed by the OS
305+ 4. Fork parent does `dup(<read pipe>, <stdin>)` and `exec(<python>)`
306+ 5. Python reads `b''` (i.e. EOF) from stdin (a closed pipe)
307+ 6. Python runs `''` (a valid script) and exits with success"""
308+
309+ proc = subprocess .Popen (
310+ args = self .args ,
311+ stdout = subprocess .PIPE ,
312+ stderr = subprocess .PIPE ,
313+ stdin = subprocess .PIPE ,
314+ )
315+
316+ # Do not send all of the data from the preamble
317+ proc .stdin .write (self .preamble [:- 128 ])
318+ proc .stdin .flush ()
319+ proc .stdin .close ()
320+ try :
321+ try :
322+ returncode = proc .wait (timeout = 10 )
323+ except TypeError :
324+ returncode = proc .wait ()
325+ except :
326+ proc .kill ()
327+ self .fail ("First stage did not handle EOF on STDIN" )
328+ else :
329+ try :
330+ self .assertEqual (0 , returncode )
331+ self .assertEqual (
332+ proc .stdout .read (),
333+ mitogen .parent .BootstrapProtocol .EC0_MARKER + b ("\n " ),
334+ )
335+ self .assertIn (
336+ b ("Error -5 while decompressing data" ),
337+ proc .stderr .read (),
338+ )
339+ finally :
340+ proc .stdout .close ()
341+ proc .stderr .close ()
0 commit comments