8000 GH-89727: Fix `os.fwalk()` recursion error on deep trees by barneygale · Pull Request #119638 · python/cpython · GitHub
[go: up one dir, main page]

Skip to content

GH-89727: Fix os.fwalk() recursion error on deep trees #119638

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
May 30, 2024
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Simplify handling of root dir slightly.
  • Loading branch information
barneygale committed May 30, 2024
commit df60bc7ed0f21179359bf33d9898e8357aac7afb
23 changes: 11 additions & 12 deletions Lib/os.py
Original file line number Diff line number Diff line change
Expand Up @@ -439,6 +439,7 @@ def walk(top, topdown=True, onerror=None, followlinks=False):
_fwalk_close = 0
_fwalk_yield = 1
_fwalk_walk = 2
_fwalk_walk_root = 3

def fwalk(top=".", topdown=True, onerror=None, *, follow_symlinks=False, dir_fd=None):
"""Directory tree generator.
Expand Down Expand Up @@ -475,7 +476,7 @@ def fwalk(top=".", topdown=True, onerror=None, *, follow_symlinks=False, dir_fd=
"""
sys.audit("os.fwalk", top, topdown, onerror, follow_symlinks, dir_fd)
top = fspath(top)
stack = [(_fwalk_walk, (True, top, dir_fd, top, None))]
stack = [(_fwalk_walk_root, top, dir_fd, top, None)]
isbytes = isinstance(top, bytes)
while stack:
yield from _fwalk(stack, isbytes, topdown, onerror, follow_symlinks)
Expand All @@ -485,15 +486,14 @@ def _fwalk(stack, isbytes, topdown, onerror, follow_symlinks):
# necessary, it can be adapted to only require O(1) FDs, see issue
# #13734.

action, value = stack.pop()
action, *value = stack.pop()
if action == _fwalk_close:
close(value)
close(value[0])
return
elif action == _fwalk_yield:
yield value
return
assert action == _fwalk_walk
isroot, toppath, dirfd, topname, entry = value
toppath, dirfd, topname, entry = value
try:
if not follow_symlinks:
# Note: To guard against symlink races, we use the standard
Expand All @@ -504,14 +504,15 @@ def _fwalk(stack, isbytes, topdown, onerror, follow_symlinks):
orig_st = entry.stat(follow_symlinks=False)
topfd = open(topname, O_RDONLY | O_NONBLOCK, dir_fd=dirfd)
except OSError as err:
if isroot:
if action == _fwalk_walk_root:
# Root of walk: propagate error from stat() or open().
raise
if onerror is not None:
onerror(err)
return
stack.append((_fwalk_close, topfd))
if not follow_symlinks:
if isroot and not st.S_ISDIR(orig_st.st_mode):
if action == _fwalk_walk_root and not st.S_ISDIR(orig_st.st_mode):
# Root of walk: ignore non-directory.
return
if not path.samestat(orig_st, stat(topfd)):
Expand Down Expand Up @@ -544,19 +545,17 @@ def _fwalk(stack, isbytes, topdown, onerror, follow_symlinks):
if topdown:
yield toppath, dirs, nondirs, topfd
else:
stack.append((_fwalk_yield, (toppath, dirs, nondirs, topfd)))
stack.append((_fwalk_yield, toppath, dirs, nondirs, topfd))

dirs = dirs[::-1]
if entries is None:
stack.extend(
(_fwalk_walk,
(False, path.join(toppath, name), topfd, name, None))
(_fwalk_walk, path.join(toppath, name), topfd, name, None)
for name in dirs)
else:
entries = entries[::-1]
stack.extend(
(_fwalk_walk,
(False, path.join(toppath, name), topfd, name, entry))
(_fwalk_walk, path.join(toppath, name), topfd, name, entry)
for name, entry in zip(dirs, entries))

__all__.append("fwalk")
Expand Down
0