49
49
else :
50
50
SETBINARY = ''
51
51
52
+ NONEXISTING_CMD = ('nonexisting_i_hope' ,)
53
+
52
54
53
55
class BaseTestCase (unittest .TestCase ):
54
56
def setUp (self ):
@@ -1120,10 +1122,11 @@ def _test_bufsize_equal_one(self, line, expected, universal_newlines):
1120
1122
p .stdin .write (line ) # expect that it flushes the line in text mode
1121
1123
os .close (p .stdin .fileno ()) # close it without flushing the buffer
1122
1124
read_line = p .stdout .readline ()
1123
- try :
1124
- p .stdin .close ()
1125
- except OSError :
1126
- pass
1125
+ with support .SuppressCrashReport ():
1126
+ try :
1127
+ p .stdin .close ()
1128
+ except OSError :
1129
+ pass
1127
1130
p .stdin = None
1128
1131
self .assertEqual (p .returncode , 0 )
1129
1132
self .assertEqual (read_line , expected )
@@ -1148,13 +1151,54 @@ def test_leaking_fds_on_error(self):
1148
1151
# 1024 times (each call leaked two fds).
1149
1152
for i in range (1024 ):
1150
1153
with self .assertRaises (OSError ) as c :
1151
- subprocess .Popen ([ 'nonexisting_i_hope' ] ,
1154
+ subprocess .Popen (NONEXISTING_CMD ,
1152
1155
stdout = subprocess .PIPE ,
1153
1156
stderr = subprocess .PIPE )
1154
1157
# ignore errors that indicate the command was not found
1155
1158
if c .exception .errno not in (errno .ENOENT , errno .EACCES ):
1156
1159
raise c .exception
1157
1160
1161
+ def test_nonexisting_with_pipes (self ):
1162
+ # bpo-30121: Popen with pipes must close properly pipes on error.
1163
+ # Previously, os.close() was called with a Windows handle which is not
1164
+ # a valid file descriptor.
1165
+ #
1166
+ # Run the test in a subprocess to control how the CRT reports errors
1167
+ # and to get stderr content.
1168
+ try :
1169
+ import msvcrt
1170
+ msvcrt .CrtSetReportMode
1171
+ except (AttributeError , ImportError ):
1172
+ self .skipTest ("need msvcrt.CrtSetReportMode" )
1173
+
1174
+ code = textwrap .dedent (f"""
1175
+ import msvcrt
1176
+ import subprocess
1177
+
1178
+ cmd = { NONEXISTING_CMD !r}
1179
+
1180
+ for report_type in [msvcrt.CRT_WARN,
1181
+ msvcrt.CRT_ERROR,
1182
+ msvcrt.CRT_ASSERT]:
1183
+ msvcrt.CrtSetReportMode(report_type, msvcrt.CRTDBG_MODE_FILE)
1184
+ msvcrt.CrtSetReportFile(report_type, msvcrt.CRTDBG_FILE_STDERR)
1185
+
1186
+ try:
1187
+ subprocess.Popen([cmd],
1188
+ stdout=subprocess.PIPE,
1189
+ stderr=subprocess.PIPE)
1190
+ except OSError:
1191
+ pass
1192
+ """ )
1193
+ cmd = [sys .executable , "-c" , code ]
1194
+ proc = subprocess .Popen (cmd ,
1195
+ stderr = subprocess .PIPE ,
1196
+ universal_newlines = True )
1197
+ with proc :
1198
+ stderr = proc .communicate ()[1 ]
1199
+ self .assertEqual (stderr , "" )
1200
+ self .assertEqual (proc .returncode , 0 )
1201
+
1158
1202
@unittest .skipIf (threading is None , "threading required" )
1159
1203
def test_double_close_on_error (self ):
1160
1204
# Issue #18851
@@ -1167,7 +1211,7 @@ def open_fds():
1167
1211
t .start ()
1168
1212
try :
1169
1213
with self .assertRaises (EnvironmentError ):
1170
- subprocess .Popen ([ 'nonexisting_i_hope' ] ,
1214
+ subprocess .Popen (NONEXISTING_CMD ,
1171
1215
stdin = subprocess .PIPE ,
1172
1216
stdout = subprocess .PIPE ,
1173
1217
stderr = subprocess .PIPE )
@@ -2433,7 +2477,7 @@ def test_leak_fast_process_del_killed(self):
2433
2477
# should trigger the wait() of p
2434
2478
time .sleep (0.2 )
2435
2479
with self .assertRaises (OSError ) as c :
2436
- with subprocess .Popen ([ 'nonexisting_i_hope' ] ,
2480
+ with subprocess .Popen (NONEXISTING_CMD ,
2437
2481
stdout = subprocess .PIPE ,
2438
2482
stderr = subprocess .PIPE ) as proc :
2439
2483
pass
@@ -2863,7 +2907,7 @@ def test_communicate_stdin(self):
2863
2907
2864
2908
def test_invalid_args (self ):
2865
2909
with self .assertRaises ((FileNotFoundError , PermissionError )) as c :
2866
- with subprocess .Popen ([ 'nonexisting_i_hope' ] ,
2910
+ with subprocess .Popen (NONEXISTING_CMD ,
2867
2911
stdout = subprocess .PIPE ,
2868
2912
stderr = subprocess .PIPE ) as proc :
2869
2913
pass
0 commit comments