New submission from Jeremy <ucod...@gmail.com>:
The way that contextlib.chdir currently restores the old working directory, an exception is raised if the program was already close to or beyond a system's PATH_MAX. The context manager has no issue crafting the path in __enter__ because os.getcwd() can return a path that is longer than PATH_MAX, but when used in __exit__ os.chdir() cannot use a path that long. I think an __exit__ should be as cautious as possible to not raise as the exception can occur far away from where the context manager was created. Its also doesn't reflect the programmer actually using the context manager incorrectly as they might not have any control or care where the process was started, yet if it happened to already be at a deep path when launched, any use of chdir anywhere would cause exceptions. I have tested this on macOS 11.13 using APFS but I am sure it would also fail on other macs and Linuxes. I don't know about Windows. Note I originally created this test as a patch to Lib/tests/test_contextlib.py but libregrtest uses os.getcwd() in its runner and that disrupts the traceback and misidentifies the cause of failure. Test file: ```python import os import shutil from contextlib import chdir def test_long_path(): # NAME_MAX of 255 long_filename = "_".join(["testdir"]*32) long_path_end = startingwd = os.getcwd() try: # I thought this would have to be 16, i.e. a path length over 4096, PATH_MAX # but seemingly just crossing 1050 is enough to fail for _ in range(4): os.mkdir(long_filename) os.chdir(long_filename) long_path_end = os.path.join(long_path_end, long_filename) os.mkdir(long_filename) long_path_end = os.path.join(long_path_end, long_filename) with chdir(long_filename): #self.assertEqual(os.getcwd(), long_path_end) assert os.getcwd() == long_path_end print("passed") finally: shutil.rmtree(os.path.join(startingwd, long_filename), ignore_errors=True) test_long_path() ``` And output: ``` $ ./python.exe ./test_chdir.py passed Traceback (most recent call last): File "/Users/ucodery/git/cpython/./test_chdir.py", line 27, in <module> test_long_path() ^^^^^^^^^^^^^^^^ File "/Users/ucodery/git/cpython/./test_chdir.py", line 19, in test_long_path with chdir(long_filename): ^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/Users/ucodery/git/cpython/Lib/contextlib.py", line 781, in __exit__ os.chdir(self._old_cwd.pop()) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ OSError: [Errno 63] File name too long: '/Users/ucodery/git/cpython/testdir_testdir_testdir_testdir_testdir_testdir_testdir_testdir_testdir_testdir_testdir_testdir_testdir_testdir_testdir_testdir_testdir_testdir_testdir_testdir_testdir_testdir_testdir_testdir_testdir_testdir_testdir_testdir_testdir_testdir_testdir_testdir/testdir_testdir_testdir_testdir_testdir_testdir_testdir_testdir_testdir_testdir_testdir_testdir_testdir_testdir_testdir_testdir_testdir_testdir_testdir_testdir_testdir_testdir_testdir_testdir_testdir_testdir_testdir_testdir_testdir_testdir_testdir_testdir/testdir_testdir_testdir_testdir_testdir_testdir_testdir_testdir_testdir_testdir_testdir_testdir_testdir_testdir_testdir_testdir_testdir_testdir_testdir_testdir_testdir_testdir_testdir_testdir_testdir_testdir_testdir_testdir_testdir_testdir_testdir_testdir/testdir_testdir_testdir_testdir_testdir_testdir_testdir_testdir_testdir_testdir_testdir_testdir_testdir_testdir_testdir_testdir_testdir_testdir_testdir_testdir_te stdir_testdir_testdir_testdir_testdir_testdir_testdir_testdir_testdir_testdir_testdir_testdir' ``` ---------- files: test_chdir.py messages: 404534 nosy: ucodery priority: normal severity: normal status: open title: chdir __exit__ is not safe type: behavior versions: Python 3.11 Added file: https://bugs.python.org/file50377/test_chdir.py _______________________________________ Python tracker <rep...@bugs.python.org> <https://bugs.python.org/issue45545> _______________________________________ _______________________________________________ Python-bugs-list mailing list Unsubscribe: https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com