gh-142155: Fix infinite recursion in shutil.copytree on Windows junctions by ChuheLin · Pull Request #142156 · python/cpython
- Issue: shutil.copytree infinite recursion crash on Windows Directory Junctions (WinError 206) #142155
Summary
This PR fixes a critical crash (WinError 206 / WinError 1921) in shutil.copytree on Windows when encountering directory junctions that point to a parent directory (recursive cycles).
The Problem
On Windows, shutil.copytree contains specific logic to force traversal into Directory Junctions by treating them as standard directories (is_symlink is forced to False).
However, unlike os.walk or shutil.rmtree (after recent fixes), copytree lacked a cycle detection mechanism for these traversed junctions. This caused infinite recursion until the path exceeded the OS limit, resulting in an unhandled OSError (Crash) rather than a Python RecursionError.
The Fix
I implemented cycle detection using file system identity (st_dev, st_ino), similar to how deepcopy handles recursion:
- Added a hidden
_seenset parameter tocopytreeand its helper_copytree. - Before entering a directory, the code now checks if
(st.st_dev, st.st_ino)is already in_seen. - If a cycle is detected, it raises a
shutil.Error("Infinite recursion detected")immediately, preventing the crash.
Verification
- Regression Test: Added
test_copytree_recursive_junctiontoLib/test/test_shutil.py.- Status: PASSED on local Windows build.
- Manual Verification: Verified with a reproduction script that previously caused a
WinError 206crash.- Before fix: Script crashed after creating a path > 4000 chars.
- After fix: Script correctly raises
shutil.Error: Infinite recursion detected.