diff options
author | Miss Islington (bot) <31488909+miss-islington@users.noreply.github.com> | 2024-05-30 04:40:21 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-05-30 04:40:21 (GMT) |
commit | 083bf3ad1795604ee833d1595f2a536b9cd57419 (patch) | |
tree | 7b21acd90198472279cffb68fe26f20c76fad447 /Lib | |
parent | 810a09ad3710be60cff9e174be85ca65e76cdbd1 (diff) | |
download | cpython-083bf3ad1795604ee833d1595f2a536b9cd57419.zip cpython-083bf3ad1795604ee833d1595f2a536b9cd57419.tar.gz cpython-083bf3ad1795604ee833d1595f2a536b9cd57419.tar.bz2 |
[3.13] GH-89727: Fix FD leak on `os.fwalk()` generator finalization. (GH-119766) (#119767)
GH-89727: Fix FD leak on `os.fwalk()` generator finalization. (GH-119766)
Follow-up to 3c890b50. Ensure we `os.close()` open file descriptors when
the `os.fwalk()` generator is finalized.
(cherry picked from commit a5fef800d31648d19cecc240a2fa0dc71371753e)
Co-authored-by: Barney Gale <barney.gale@gmail.com>
Diffstat (limited to 'Lib')
-rw-r--r-- | Lib/os.py | 11 | ||||
-rw-r--r-- | Lib/test/test_os.py | 21 |
2 files changed, 30 insertions, 2 deletions
@@ -480,8 +480,15 @@ if {open, stat} <= supports_dir_fd and {scandir, stat} <= supports_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) diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py index 7dc5784..de5a86f 100644 --- a/Lib/test/test_os.py +++ b/Lib/test/test_os.py @@ -1685,6 +1685,27 @@ class FwalkTests(WalkTests): 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 |