[New-bugs-announce] [issue45545] chdir __exit__ is not safe

Jeremy report at bugs.python.org
Wed Oct 20 18:54:45 EDT 2021


New submission from Jeremy <ucodery at 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_testdir_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 <report at bugs.python.org>
<https://bugs.python.org/issue45545>
_______________________________________


More information about the New-bugs-announce mailing list