Skip to content

Commit

Permalink
[3.12] GH-89727: Fix FD leak on os.fwalk() generator finalization. (G…
Browse files Browse the repository at this point in the history
…H-119766) (#119768)

GH-89727: Fix FD leak on `os.fwalk()` generator finalization. (GH-119766)

Follow-up to 3c890b5. Ensure we `os.close()` open file descriptors when
the `os.fwalk()` generator is finalized.
(cherry picked from commit a5fef80)

Co-authored-by: Barney Gale <[email protected]>
  • Loading branch information
miss-islington and barneygale authored May 30, 2024
1 parent aae371b commit d4a146d
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 2 deletions.
11 changes: 9 additions & 2 deletions Lib/os.py
Original file line number Diff line number Diff line change
Expand Up @@ -478,8 +478,15 @@ def fwalk(top=".", topdown=True, onerror=None, *, follow_symlinks=False, dir_fd=
top = fspath(top)
stack = [(_fwalk_walk, (True, dir_fd, top, top, None))]
isbytes = isinstance(top, bytes)
while stack:
yield from _fwalk(stack, isbytes, topdown, onerror, follow_symlinks)
try:
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).
_fwalk_walk = 0 # args: (isroot, dirfd, toppath, topname, entry)
Expand Down
21 changes: 21 additions & 0 deletions Lib/test/test_os.py
Original file line number Diff line number Diff line change
Expand Up @@ -1671,6 +1671,27 @@ def test_fd_leak(self):
self.addCleanup(os.close, newfd)
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
test_walk_many_open_files = None

Expand Down

0 comments on commit d4a146d

Please sign in to comment.