mirror of https://github.com/python/cpython
GH-89727: Fix FD leak on `os.fwalk()` generator finalization. (#119766)
Follow-up to 3c890b50
. Ensure we `os.close()` open file descriptors when
the `os.fwalk()` generator is finalized.
This commit is contained in:
parent
3c890b503c
commit
a5fef800d3
11
Lib/os.py
11
Lib/os.py
|
@ -480,8 +480,15 @@ if {open, stat} <= supports_dir_fd and {scandir, stat} <= supports_fd:
|
||||||
top = fspath(top)
|
top = fspath(top)
|
||||||
stack = [(_fwalk_walk, (True, dir_fd, top, top, None))]
|
stack = [(_fwalk_walk, (True, dir_fd, top, top, None))]
|
||||||
isbytes = isinstance(top, bytes)
|
isbytes = isinstance(top, bytes)
|
||||||
while stack:
|
try:
|
||||||
yield from _fwalk(stack, isbytes, topdown, onerror, follow_symlinks)
|
while stack:
|
||||||
|
yield from _fwalk(stack, isbytes, topdown, onerror, follow_symlinks)
|
||||||
|
finally:
|
||||||
|
# Close any file descriptors still on the stack.
|
||||||
|
while stack:
|
||||||
|
action, value = stack.pop()
|
||||||
|
if action == _fwalk_close:
|
||||||
|
close(value)
|
||||||
|
|
||||||
# Each item in the _fwalk() stack is a pair (action, args).
|
# Each item in the _fwalk() stack is a pair (action, args).
|
||||||
_fwalk_walk = 0 # args: (isroot, dirfd, toppath, topname, entry)
|
_fwalk_walk = 0 # args: (isroot, dirfd, toppath, topname, entry)
|
||||||
|
|
|
@ -1685,6 +1685,27 @@ class FwalkTests(WalkTests):
|
||||||
self.addCleanup(os.close, newfd)
|
self.addCleanup(os.close, newfd)
|
||||||
self.assertEqual(newfd, minfd)
|
self.assertEqual(newfd, minfd)
|
||||||
|
|
||||||
|
@unittest.skipIf(
|
||||||
|
support.is_emscripten, "Cannot dup stdout on Emscripten"
|
||||||
|
)
|
||||||
|
@unittest.skipIf(
|
||||||
|
support.is_android, "dup return value is unpredictable on Android"
|
||||||
|
)
|
||||||
|
def test_fd_finalization(self):
|
||||||
|
# Check that close()ing the fwalk() generator closes FDs
|
||||||
|
def getfd():
|
||||||
|
fd = os.dup(1)
|
||||||
|
os.close(fd)
|
||||||
|
return fd
|
||||||
|
for topdown in (False, True):
|
||||||
|
old_fd = getfd()
|
||||||
|
it = self.fwalk(os_helper.TESTFN, topdown=topdown)
|
||||||
|
self.assertEqual(getfd(), old_fd)
|
||||||
|
next(it)
|
||||||
|
self.assertGreater(getfd(), old_fd)
|
||||||
|
it.close()
|
||||||
|
self.assertEqual(getfd(), old_fd)
|
||||||
|
|
||||||
# fwalk() keeps file descriptors open
|
# fwalk() keeps file descriptors open
|
||||||
test_walk_many_open_files = None
|
test_walk_many_open_files = None
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue