Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 4f61b02

Browse files
committed
Issue #10963: Ensure that subprocess.communicate() never raises EPIPE.
1 parent 45fdb45 commit 4f61b02

3 files changed

Lines changed: 55 additions & 11 deletions

File tree

Lib/subprocess.py

Lines changed: 34 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,7 @@ class Popen(args, bufsize=0, executable=None,
326326
import traceback
327327
import gc
328328
import signal
329+
import errno
329330

330331
# Exception classes used by this module.
331332
class CalledProcessError(Exception):
@@ -358,7 +359,6 @@ class pywintypes:
358359
else:
359360
import select
360361
_has_poll = hasattr(select, 'poll')
361-
import errno
362362
import fcntl
363363
import pickle
364364

@@ -699,7 +699,11 @@ def communicate(self, input=None):
699699
stderr = None
700700
if self.stdin:
701701
if input:
702-
self.stdin.write(input)
702+
try:
703+
self.stdin.write(input)
704+
except IOError as e:
705+
if e.errno != errno.EPIPE and e.errno != errno.EINVAL:
706+
raise
703707
self.stdin.close()
704708
elif self.stdout:
705709
stdout = self.stdout.read()
@@ -929,7 +933,11 @@ def _communicate(self, input):
929933

930934
if self.stdin:
931935
if input is not None:
932-
self.stdin.write(input)
936+
try:
937+
self.stdin.write(input)
938+
except IOError as e:
939+
if e.errno != errno.EPIPE:
940+
raise
933941
self.stdin.close()
934942

935943
if self.stdout:
@@ -1290,9 +1298,16 @@ def close_unregister_and_remove(fd):
12901298
for fd, mode in ready:
12911299
if mode & select.POLLOUT:
12921300
chunk = input[input_offset : input_offset + _PIPE_BUF]
1293-
input_offset += os.write(fd, chunk)
1294-
if input_offset >= len(input):
1295-
close_unregister_and_remove(fd)
1301+
try:
1302+
input_offset += os.write(fd, chunk)
1303+
except OSError as e:
1304+
if e.errno == errno.EPIPE:
1305+
close_unregister_and_remove(fd)
1306+
else:
1307+
raise
1308+
else:
1309+
if input_offset >= len(input):
1310+
close_unregister_and_remove(fd)
12961311
elif mode & select_POLLIN_POLLPRI:
12971312
data = os.read(fd, 4096)
12981313
if not data:
@@ -1334,11 +1349,19 @@ def _communicate_with_select(self, input):
13341349

13351350
if self.stdin in wlist:
13361351
chunk = input[input_offset : input_offset + _PIPE_BUF]
1337-
bytes_written = os.write(self.stdin.fileno(), chunk)
1338-
input_offset += bytes_written
1339-
if input_offset >= len(input):
1340-
self.stdin.close()
1341-
write_set.remove(self.stdin)
1352+
try:
1353+
bytes_written = os.write(self.stdin.fileno(), chunk)
1354+
except OSError as e:
1355+
if e.errno == errno.EPIPE:
1356+
self.stdin.close()
1357+
write_set.remove(self.stdin)
1358+
else:
1359+
raise
1360+
else:
1361+
input_offset += bytes_written
1362+
if input_offset >= len(input):
1363+
self.stdin.close()
1364+
write_set.remove(self.stdin)
13421365

13431366
if self.stdout in rlist:
13441367
data = os.read(self.stdout.fileno(), 1024)

Lib/test/test_subprocess.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -592,6 +592,25 @@ def test_handles_closed_on_exception(self):
592592
self.assertFalse(os.path.exists(ofname))
593593
self.assertFalse(os.path.exists(efname))
594594

595+
def test_communicate_epipe(self):
596+
# Issue 10963: communicate() should hide EPIPE
597+
p = subprocess.Popen([sys.executable, "-c", 'pass'],
598+
stdin=subprocess.PIPE,
599+
stdout=subprocess.PIPE,
600+
stderr=subprocess.PIPE)
601+
self.addCleanup(p.stdout.close)
602+
self.addCleanup(p.stderr.close)
603+
self.addCleanup(p.stdin.close)
604+
p.communicate(b"x" * 2**20)
605+
606+
def test_communicate_epipe_only_stdin(self):
607+
# Issue 10963: communicate() should hide EPIPE
608+
p = subprocess.Popen([sys.executable, "-c", 'pass'],
609+
stdin=subprocess.PIPE)
610+
self.addCleanup(p.stdin.close)
611+
time.sleep(2)
612+
p.communicate(b"x" * 2**20)
613+
595614
#
596615
# POSIX tests
597616
#

Misc/NEWS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ Core and Builtins
4444
Library
4545
-------
4646

47+
- Issue #10963: Ensure that subprocess.communicate() never raises EPIPE.
48+
4749
- Issue #11696: Fix ID generation in msilib.
4850

4951
- Issue #9696: Fix exception incorrectly raised by xdrlib.Packer.pack_int when

0 commit comments

Comments
 (0)