Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
cpython
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
cpython
Commits
558639f0
Commit
558639f0
authored
Aug 18, 2011
by
Charles-François Natali
Browse files
Options
Browse Files
Download
Plain Diff
Issue #12650: Fix a race condition where a subprocess.Popen could leak
resources (FD/zombie) when killed at the wrong time.
parents
020340f2
134a8bae
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
67 additions
and
1 deletion
+67
-1
Lib/subprocess.py
Lib/subprocess.py
+6
-1
Lib/test/test_subprocess.py
Lib/test/test_subprocess.py
+58
-0
Misc/NEWS
Misc/NEWS
+3
-0
No files found.
Lib/subprocess.py
View file @
558639f0
...
...
@@ -424,12 +424,16 @@ try:
except
:
MAXFD
=
256
# This lists holds Popen instances for which the underlying process had not
# exited at the time its __del__ method got called: those processes are wait()ed
# for synchronously from _cleanup() when a new Popen object is created, to avoid
# zombie processes.
_active
=
[]
def
_cleanup
():
for
inst
in
_active
[:]:
res
=
inst
.
_internal_poll
(
_deadstate
=
sys
.
maxsize
)
if
res
is
not
None
and
res
>=
0
:
if
res
is
not
None
:
try
:
_active
.
remove
(
inst
)
except
ValueError
:
...
...
@@ -1272,6 +1276,7 @@ class Popen(object):
errread
,
errwrite
,
errpipe_read
,
errpipe_write
,
restore_signals
,
start_new_session
,
preexec_fn
)
self
.
_child_created
=
True
finally
:
# be sure the FD is closed no matter what
os
.
close
(
errpipe_write
)
...
...
Lib/test/test_subprocess.py
View file @
558639f0
...
...
@@ -1491,6 +1491,64 @@ class POSIXProcessTestCase(BaseTestCase):
finally
:
p
.
wait
()
def
test_zombie_fast_process_del
(
self
):
# Issue #12650: on Unix, if Popen.__del__() was called before the
# process exited, it wouldn't be added to subprocess._active, and would
# remain a zombie.
# spawn a Popen, and delete its reference before it exits
p
=
subprocess
.
Popen
([
sys
.
executable
,
"-c"
,
'import sys, time;'
'time.sleep(0.2)'
],
stdout
=
subprocess
.
PIPE
,
stderr
=
subprocess
.
PIPE
)
ident
=
id
(
p
)
pid
=
p
.
pid
del
p
# check that p is in the active processes list
self
.
assertIn
(
ident
,
[
id
(
o
)
for
o
in
subprocess
.
_active
])
# sleep a little to let the process exit, and create a new Popen: this
# should trigger the wait() of p
time
.
sleep
(
1
)
with
self
.
assertRaises
(
EnvironmentError
)
as
c
:
with
subprocess
.
Popen
([
'nonexisting_i_hope'
],
stdout
=
subprocess
.
PIPE
,
stderr
=
subprocess
.
PIPE
)
as
proc
:
pass
# p should have been wait()ed on, and removed from the _active list
self
.
assertRaises
(
OSError
,
os
.
waitpid
,
pid
,
0
)
self
.
assertNotIn
(
ident
,
[
id
(
o
)
for
o
in
subprocess
.
_active
])
def
test_leak_fast_process_del_killed
(
self
):
# Issue #12650: on Unix, if Popen.__del__() was called before the
# process exited, and the process got killed by a signal, it would never
# be removed from subprocess._active, which triggered a FD and memory
# leak.
# spawn a Popen, delete its reference and kill it
p
=
subprocess
.
Popen
([
sys
.
executable
,
"-c"
,
'import time;'
'time.sleep(3)'
],
stdout
=
subprocess
.
PIPE
,
stderr
=
subprocess
.
PIPE
)
ident
=
id
(
p
)
pid
=
p
.
pid
del
p
os
.
kill
(
pid
,
signal
.
SIGKILL
)
# check that p is in the active processes list
self
.
assertIn
(
ident
,
[
id
(
o
)
for
o
in
subprocess
.
_active
])
# let some time for the process to exit, and create a new Popen: this
# should trigger the wait() of p
time
.
sleep
(
0.2
)
with
self
.
assertRaises
(
EnvironmentError
)
as
c
:
with
subprocess
.
Popen
([
'nonexisting_i_hope'
],
stdout
=
subprocess
.
PIPE
,
stderr
=
subprocess
.
PIPE
)
as
proc
:
pass
# p should have been wait()ed on, and removed from the _active list
self
.
assertRaises
(
OSError
,
os
.
waitpid
,
pid
,
0
)
self
.
assertNotIn
(
ident
,
[
id
(
o
)
for
o
in
subprocess
.
_active
])
@
unittest
.
skipUnless
(
mswindows
,
"Windows specific tests"
)
class
Win32ProcessTestCase
(
BaseTestCase
):
...
...
Misc/NEWS
View file @
558639f0
...
...
@@ -262,6 +262,9 @@ Core and Builtins
Library
-------
- Issue #12650: Fix a race condition where a subprocess.Popen could leak
resources (FD/zombie) when killed at the wrong time.
- Issue #12744: Fix inefficient representation of integers between 2**31 and
2**63 on systems with a 64-bit C "long".
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment