summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Lib/test/test_posix.py22
-rw-r--r--Misc/NEWS.d/next/macOS/2022-10-05-15-26-58.gh-issue-97897.Rf-C6u.rst6
-rw-r--r--Modules/posixmodule.c60
3 files changed, 80 insertions, 8 deletions
diff --git a/Lib/test/test_posix.py b/Lib/test/test_posix.py
index 6ba1454..3c0ddeb 100644
--- a/Lib/test/test_posix.py
+++ b/Lib/test/test_posix.py
@@ -2040,6 +2040,28 @@ class TestPosixWeaklinking(unittest.TestCase):
with self.assertRaisesRegex(NotImplementedError, "dir_fd unavailable"):
os.mkdir("dir", dir_fd=0)
+ def test_mkfifo(self):
+ self._verify_available("HAVE_MKFIFOAT")
+ if self.mac_ver >= (13, 0):
+ self.assertIn("HAVE_MKFIFOAT", posix._have_functions)
+
+ else:
+ self.assertNotIn("HAVE_MKFIFOAT", posix._have_functions)
+
+ with self.assertRaisesRegex(NotImplementedError, "dir_fd unavailable"):
+ os.mkfifo("path", dir_fd=0)
+
+ def test_mknod(self):
+ self._verify_available("HAVE_MKNODAT")
+ if self.mac_ver >= (13, 0):
+ self.assertIn("HAVE_MKNODAT", posix._have_functions)
+
+ else:
+ self.assertNotIn("HAVE_MKNODAT", posix._have_functions)
+
+ with self.assertRaisesRegex(NotImplementedError, "dir_fd unavailable"):
+ os.mknod("path", dir_fd=0)
+
def test_rename_replace(self):
self._verify_available("HAVE_RENAMEAT")
if self.mac_ver >= (10, 10):
diff --git a/Misc/NEWS.d/next/macOS/2022-10-05-15-26-58.gh-issue-97897.Rf-C6u.rst b/Misc/NEWS.d/next/macOS/2022-10-05-15-26-58.gh-issue-97897.Rf-C6u.rst
new file mode 100644
index 0000000..0d21e98
--- /dev/null
+++ b/Misc/NEWS.d/next/macOS/2022-10-05-15-26-58.gh-issue-97897.Rf-C6u.rst
@@ -0,0 +1,6 @@
+The macOS 13 SDK includes support for the ``mkfifoat`` and ``mknodat`` system calls.
+Using the ``dir_fd`` option with either :func:`os.mkfifo` or :func:`os.mknod` could result in a
+segfault if cpython is built with the macOS 13 SDK but run on an earlier
+version of macOS. Prevent this by adding runtime support for detection of
+these system calls ("weaklinking") as is done for other newer syscalls on
+macOS.
diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c
index 1270af7..bf4e648 100644
--- a/Modules/posixmodule.c
+++ b/Modules/posixmodule.c
@@ -79,6 +79,8 @@
# define HAVE_FUTIMENS_RUNTIME __builtin_available(macOS 10.13, iOS 11.0, tvOS 11.0, watchOS 4.0, *)
# define HAVE_UTIMENSAT_RUNTIME __builtin_available(macOS 10.13, iOS 11.0, tvOS 11.0, watchOS 4.0, *)
# define HAVE_PWRITEV_RUNTIME __builtin_available(macOS 11.0, iOS 14.0, tvOS 14.0, watchOS 7.0, *)
+# define HAVE_MKFIFOAT_RUNTIME __builtin_available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *)
+# define HAVE_MKNODAT_RUNTIME __builtin_available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *)
# define HAVE_POSIX_SPAWN_SETSID_RUNTIME __builtin_available(macOS 10.15, *)
@@ -163,6 +165,8 @@
# define HAVE_FUTIMENS_RUNTIME 1
# define HAVE_UTIMENSAT_RUNTIME 1
# define HAVE_PWRITEV_RUNTIME 1
+# define HAVE_MKFIFOAT_RUNTIME 1
+# define HAVE_MKNODAT_RUNTIME 1
#endif
@@ -10482,18 +10486,35 @@ os_mkfifo_impl(PyObject *module, path_t *path, int mode, int dir_fd)
{
int result;
int async_err = 0;
+#ifdef HAVE_MKFIFOAT
+ int mkfifoat_unavailable = 0;
+#endif
do {
Py_BEGIN_ALLOW_THREADS
#ifdef HAVE_MKFIFOAT
- if (dir_fd != DEFAULT_DIR_FD)
- result = mkfifoat(dir_fd, path->narrow, mode);
- else
+ if (dir_fd != DEFAULT_DIR_FD) {
+ if (HAVE_MKFIFOAT_RUNTIME) {
+ result = mkfifoat(dir_fd, path->narrow, mode);
+
+ } else {
+ mkfifoat_unavailable = 1;
+ result = 0;
+ }
+ } else
#endif
result = mkfifo(path->narrow, mode);
Py_END_ALLOW_THREADS
} while (result != 0 && errno == EINTR &&
!(async_err = PyErr_CheckSignals()));
+
+#ifdef HAVE_MKFIFOAT
+ if (mkfifoat_unavailable) {
+ argument_unavailable_error(NULL, "dir_fd");
+ return NULL;
+ }
+#endif
+
if (result != 0)
return (!async_err) ? posix_error() : NULL;
@@ -10534,18 +10555,33 @@ os_mknod_impl(PyObject *module, path_t *path, int mode, dev_t device,
{
int result;
int async_err = 0;
+#ifdef HAVE_MKNODAT
+ int mknodat_unavailable = 0;
+#endif
do {
Py_BEGIN_ALLOW_THREADS
#ifdef HAVE_MKNODAT
- if (dir_fd != DEFAULT_DIR_FD)
- result = mknodat(dir_fd, path->narrow, mode, device);
- else
+ if (dir_fd != DEFAULT_DIR_FD) {
+ if (HAVE_MKNODAT_RUNTIME) {
+ result = mknodat(dir_fd, path->narrow, mode, device);
+
+ } else {
+ mknodat_unavailable = 1;
+ result = 0;
+ }
+ } else
#endif
result = mknod(path->narrow, mode, device);
Py_END_ALLOW_THREADS
} while (result != 0 && errno == EINTR &&
!(async_err = PyErr_CheckSignals()));
+#ifdef HAVE_MKNODAT
+ if (mknodat_unavailable) {
+ argument_unavailable_error(NULL, "dir_fd");
+ return NULL;
+ }
+#endif
if (result != 0)
return (!async_err) ? posix_error() : NULL;
@@ -15265,6 +15301,14 @@ PROBE(probe_fdopendir, HAVE_FDOPENDIR_RUNTIME)
PROBE(probe_mkdirat, HAVE_MKDIRAT_RUNTIME)
#endif
+#ifdef HAVE_MKFIFOAT
+PROBE(probe_mkfifoat, HAVE_MKFIFOAT_RUNTIME)
+#endif
+
+#ifdef HAVE_MKNODAT
+PROBE(probe_mknodat, HAVE_MKNODAT_RUNTIME)
+#endif
+
#ifdef HAVE_RENAMEAT
PROBE(probe_renameat, HAVE_RENAMEAT_RUNTIME)
#endif
@@ -15394,11 +15438,11 @@ static const struct have_function {
#endif
#ifdef HAVE_MKFIFOAT
- { "HAVE_MKFIFOAT", NULL },
+ { "HAVE_MKFIFOAT", probe_mkfifoat },
#endif
#ifdef HAVE_MKNODAT
- { "HAVE_MKNODAT", NULL },
+ { "HAVE_MKNODAT", probe_mknodat },
#endif
#ifdef HAVE_OPENAT