From be1ac9c16cd13aef106e5aeab290636f32021137 Mon Sep 17 00:00:00 2001 From: Shantanu <12621235+hauntsaninja@users.noreply.github.com> Date: Thu, 6 Mar 2025 23:41:28 -0800 Subject: [PATCH] gh-130932: Fix incorrect exception handling in _PyModule_IsPossiblyShadowing (GH-130934) I chose to not raise an exception here because I think it would be confusing for module attribute access to start raising something other than AttributeError if e.g. the cwd goes away Without the change in moduleobject.c ``` ./python.exe -m unittest test.test_import.ImportTests.test_script_shadowing_stdlib_cwd_failure ... Assertion failed: (PyErr_Occurred()), function _PyObject_SetAttributeErrorContext, file object.c, line 1253. ``` (cherry picked from commit 0a9ae5ed48e6ea078f67ba03635c1c26209b5def) Co-authored-by: Shantanu <12621235+hauntsaninja@users.noreply.github.com> --- Lib/test/test_import/__init__.py | 22 +++++++++++++++++++ ...-03-06-22-56-02.gh-issue-130932.QVHaKT.rst | 1 + Objects/moduleobject.c | 4 +++- 3 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2025-03-06-22-56-02.gh-issue-130932.QVHaKT.rst diff --git a/Lib/test/test_import/__init__.py b/Lib/test/test_import/__init__.py index c5a545777a9ae6..9fd4dd4ed48e74 100644 --- a/Lib/test/test_import/__init__.py +++ b/Lib/test/test_import/__init__.py @@ -1203,6 +1203,28 @@ class substr(str): for line in lines: self.assertRegex(line, rb"cannot import name 'Fraction' from 'fractions' \(.*\)") + @unittest.skipIf(sys.platform == 'win32', 'Cannot delete cwd on Windows') + def test_script_shadowing_stdlib_cwd_failure(self): + with os_helper.temp_dir() as tmp: + subtmp = os.path.join(tmp, "subtmp") + os.mkdir(subtmp) + with open(os.path.join(subtmp, "main.py"), "w", encoding='utf-8') as f: + f.write(f""" +import sys +assert sys.path[0] == '' + +import os +import shutil +shutil.rmtree(os.getcwd()) + +os.does_not_exist +""") + # Use -c to ensure sys.path[0] is "" + popen = script_helper.spawn_python("-c", "import main", cwd=subtmp) + stdout, stderr = popen.communicate() + expected_error = rb"AttributeError: module 'os' has no attribute 'does_not_exist'" + self.assertRegex(stdout, expected_error) + def test_script_shadowing_stdlib_sys_path_modification(self): script_errors = [ ( diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-03-06-22-56-02.gh-issue-130932.QVHaKT.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-03-06-22-56-02.gh-issue-130932.QVHaKT.rst new file mode 100644 index 00000000000000..e12b5b88cb59ab --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-03-06-22-56-02.gh-issue-130932.QVHaKT.rst @@ -0,0 +1 @@ +Fix incorrect exception handling in ``_PyModule_IsPossiblyShadowing`` diff --git a/Objects/moduleobject.c b/Objects/moduleobject.c index 41133cb7ede22a..37faaaf7d19303 100644 --- a/Objects/moduleobject.c +++ b/Objects/moduleobject.c @@ -908,7 +908,9 @@ _PyModule_IsPossiblyShadowing(PyObject *origin) if (sys_path_0[0] == L'\0') { // if sys.path[0] == "", treat it as if it were the current directory if (!_Py_wgetcwd(sys_path_0_buf, MAXPATHLEN)) { - return -1; + // If we failed to getcwd, don't raise an exception and instead + // let the caller proceed assuming no shadowing + return 0; } sys_path_0 = sys_path_0_buf; }