From 3c693cce6eba63744cd352a5cf654c4d35339039 Mon Sep 17 00:00:00 2001 From: AN Long Date: Sun, 1 Mar 2026 22:15:39 +0900 Subject: [PATCH 1/4] Fix crash when passing -1 as fd in os.pathconf --- Lib/test/test_os/test_os.py | 10 ++++++++++ Modules/posixmodule.c | 9 ++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_os/test_os.py b/Lib/test/test_os/test_os.py index 82c55c8ba33065..80c42bdf62f3d6 100644 --- a/Lib/test/test_os/test_os.py +++ b/Lib/test/test_os/test_os.py @@ -2778,6 +2778,16 @@ def test_fpathconf_bad_fd(self): self.check(os.pathconf, "PC_NAME_MAX") self.check(os.fpathconf, "PC_NAME_MAX") + @unittest.skipUnless(hasattr(os, 'pathconf'), 'test needs os.pathconf()') + @unittest.skipIf( + support.linked_to_musl(), + 'musl pathconf ignores the file descriptor and returns a constant', + ) + def test_pathconf_negative_fd_uses_fd_semantics(self): + with self.assertRaises(OSError) as ctx: + os.pathconf(-1, 1) + self.assertEqual(ctx.exception.errno, errno.EBADF) + @unittest.skipUnless(hasattr(os, 'ftruncate'), 'test needs os.ftruncate()') def test_ftruncate(self): self.check(os.truncate, 0) diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index 8d38e034aa6b5e..0ed2ceee6b4c0f 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -1609,6 +1609,12 @@ follow_symlinks_specified(const char *function_name, int follow_symlinks) return 1; } +static bool +path_is_fd(const path_t *path) +{ + return path->allow_fd && path->object != NULL && PyIndex_Check(path->object); +} + static int path_and_dir_fd_invalid(const char *function_name, path_t *path, int dir_fd) { @@ -14328,8 +14334,9 @@ os_pathconf_impl(PyObject *module, path_t *path, int name) errno = 0; #ifdef HAVE_FPATHCONF - if (path->fd != -1) + if (path_is_fd(path)) { limit = fpathconf(path->fd, name); + } else #endif limit = pathconf(path->narrow, name); From bac84ce54991e763f19290f0e0657b6a5937ead0 Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Sun, 1 Mar 2026 13:37:41 +0000 Subject: [PATCH 2/4] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20blu?= =?UTF-8?q?rb=5Fit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../2026-03-01-13-37-31.gh-issue-145335.e36kPJ.rst | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-03-01-13-37-31.gh-issue-145335.e36kPJ.rst diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-03-01-13-37-31.gh-issue-145335.e36kPJ.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-03-01-13-37-31.gh-issue-145335.e36kPJ.rst new file mode 100644 index 00000000000000..42ed85c7da31ac --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-03-01-13-37-31.gh-issue-145335.e36kPJ.rst @@ -0,0 +1,2 @@ +Fix a crash in :func:`os.pathconf` when called with ``-1`` as the path +argument. From d0ed838e47320f6c58a9f45f93c60c039753c68b Mon Sep 17 00:00:00 2001 From: AN Long Date: Tue, 3 Mar 2026 01:38:41 +0900 Subject: [PATCH 3/4] Using is_fd field to determin a path_t is an fd or not --- Modules/posixmodule.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index 0ed2ceee6b4c0f..b82f08e7dc4291 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -1280,6 +1280,8 @@ get_posix_state(PyObject *module) * Contains a file descriptor if path.accept_fd was true * and the caller provided a signed integer instead of any * sort of string. + * path.is_fd + * True if path was provided as a file descriptor. * * WARNING: if your "path" parameter is optional, and is * unspecified, path_converter will never get called. @@ -1332,6 +1334,7 @@ typedef struct { const wchar_t *wide; const char *narrow; int fd; + bool is_fd; int value_error; Py_ssize_t length; PyObject *object; @@ -1341,7 +1344,7 @@ typedef struct { #define PATH_T_INITIALIZE(function_name, argument_name, nullable, nonstrict, \ make_wide, suppress_value_error, allow_fd) \ {function_name, argument_name, nullable, nonstrict, make_wide, \ - suppress_value_error, allow_fd, NULL, NULL, -1, 0, 0, NULL, NULL} + suppress_value_error, allow_fd, NULL, NULL, -1, false, 0, 0, NULL, NULL} #ifdef MS_WINDOWS #define PATH_T_INITIALIZE_P(function_name, argument_name, nullable, \ nonstrict, suppress_value_error, allow_fd) \ @@ -1475,6 +1478,7 @@ path_converter(PyObject *o, void *p) } path->wide = NULL; path->narrow = NULL; + path->is_fd = true; goto success_exit; } else { @@ -1609,12 +1613,6 @@ follow_symlinks_specified(const char *function_name, int follow_symlinks) return 1; } -static bool -path_is_fd(const path_t *path) -{ - return path->allow_fd && path->object != NULL && PyIndex_Check(path->object); -} - static int path_and_dir_fd_invalid(const char *function_name, path_t *path, int dir_fd) { @@ -14334,7 +14332,7 @@ os_pathconf_impl(PyObject *module, path_t *path, int name) errno = 0; #ifdef HAVE_FPATHCONF - if (path_is_fd(path)) { + if (path->is_fd) { limit = fpathconf(path->fd, name); } else From 43334faad082be65090ed4cba82062eecf80f2b4 Mon Sep 17 00:00:00 2001 From: AN Long Date: Tue, 3 Mar 2026 01:41:32 +0900 Subject: [PATCH 4/4] Fix skip messages --- Lib/test/test_os/test_os.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_os/test_os.py b/Lib/test/test_os/test_os.py index 80c42bdf62f3d6..1f241609da80cd 100644 --- a/Lib/test/test_os/test_os.py +++ b/Lib/test/test_os/test_os.py @@ -2781,7 +2781,7 @@ def test_fpathconf_bad_fd(self): @unittest.skipUnless(hasattr(os, 'pathconf'), 'test needs os.pathconf()') @unittest.skipIf( support.linked_to_musl(), - 'musl pathconf ignores the file descriptor and returns a constant', + 'musl fpathconf ignores the file descriptor and returns a constant', ) def test_pathconf_negative_fd_uses_fd_semantics(self): with self.assertRaises(OSError) as ctx: