From d0ab8f55a571394e51aa336b6a565f0a36e2f390 Mon Sep 17 00:00:00 2001 From: Omar Sandoval Date: Thu, 25 Jul 2024 16:28:35 -0700 Subject: [PATCH] libbtrfsutil: python: fix build on Python 3.13 Python 3.13, currently in beta, removed the internal _PyObject_LookupSpecial function. The libbtrfsutil Python bindings use it in the path_converter() function because it was based on internal path_converter() function in CPython [1]. This is causing build failures on Fedora Rawhide [2] and Gentoo [3]. Replace path_converter() with a version that only uses public functions based on the one in drgn [4]. 1: https://github.com/python/cpython/blob/d9efa45d7457b0dfea467bb1c2d22c69056ffc73/Modules/posixmodule.c#L1253 2: https://bugzilla.redhat.com/show_bug.cgi?id=2245650 3: https://github.com/kdave/btrfs-progs/issues/838 4: https://github.com/osandov/drgn/blob/9ad29fd86499eb32847473e928b6540872d3d59a/libdrgn/python/util.c#L81 Issue: #838 Reported-by: Neal Gompa Reported-by: Sam James Reviewed-by: Neal Gompa Signed-off-by: Omar Sandoval Signed-off-by: David Sterba --- libbtrfsutil/python/btrfsutilpy.h | 7 +-- libbtrfsutil/python/module.c | 97 ++++++++++--------------------- 2 files changed, 32 insertions(+), 72 deletions(-) diff --git a/libbtrfsutil/python/btrfsutilpy.h b/libbtrfsutil/python/btrfsutilpy.h index ee70c23a..49702dcc 100644 --- a/libbtrfsutil/python/btrfsutilpy.h +++ b/libbtrfsutil/python/btrfsutilpy.h @@ -40,16 +40,13 @@ extern PyTypeObject SubvolumeInfo_type; extern PyTypeObject SubvolumeIterator_type; extern PyTypeObject QgroupInherit_type; -/* - * Helpers for path arguments based on posixmodule.c in CPython. - */ struct path_arg { bool allow_fd; - char *path; int fd; + char *path; Py_ssize_t length; PyObject *object; - PyObject *cleanup; + PyObject *bytes; }; int path_converter(PyObject *o, void *p); void path_cleanup(struct path_arg *path); diff --git a/libbtrfsutil/python/module.c b/libbtrfsutil/python/module.c index 2657ee28..ae4651e7 100644 --- a/libbtrfsutil/python/module.c +++ b/libbtrfsutil/python/module.c @@ -44,85 +44,48 @@ static int fd_converter(PyObject *o, void *p) int path_converter(PyObject *o, void *p) { struct path_arg *path = p; - int is_index, is_bytes, is_unicode; - PyObject *bytes = NULL; - Py_ssize_t length = 0; - char *tmp; if (o == NULL) { path_cleanup(p); return 1; } - path->object = path->cleanup = NULL; - Py_INCREF(o); - path->fd = -1; + path->path = NULL; + path->length = 0; + path->bytes = NULL; + if (path->allow_fd && PyIndex_Check(o)) { + PyObject *fd_obj; + int overflow; + long fd; - is_index = path->allow_fd && PyIndex_Check(o); - is_bytes = PyBytes_Check(o); - is_unicode = PyUnicode_Check(o); - - if (!is_index && !is_bytes && !is_unicode) { - _Py_IDENTIFIER(__fspath__); - PyObject *func; - - func = _PyObject_LookupSpecial(o, &PyId___fspath__); - if (func == NULL) - goto err_format; - Py_DECREF(o); - o = PyObject_CallFunctionObjArgs(func, NULL); - Py_DECREF(func); - if (o == NULL) + fd_obj = PyNumber_Index(o); + if (!fd_obj) return 0; - is_bytes = PyBytes_Check(o); - is_unicode = PyUnicode_Check(o); - } - - if (is_unicode) { - if (!PyUnicode_FSConverter(o, &bytes)) - goto err; - } else if (is_bytes) { - bytes = o; - Py_INCREF(bytes); - } else if (is_index) { - if (!fd_converter(o, &path->fd)) - goto err; - path->path = NULL; - goto out; + fd = PyLong_AsLongAndOverflow(fd_obj, &overflow); + Py_DECREF(fd_obj); + if (fd == -1 && PyErr_Occurred()) + return 0; + if (overflow > 0 || fd > INT_MAX) { + PyErr_SetString(PyExc_OverflowError, "fd is greater than maximum"); + return 0; + } + if (fd < 0) { + PyErr_SetString(PyExc_ValueError, "fd is negative"); + return 0; + } + path->fd = fd; } else { -err_format: - PyErr_Format(PyExc_TypeError, "expected %s, not %s", - path->allow_fd ? "string, bytes, os.PathLike, or integer" : - "string, bytes, or os.PathLike", - Py_TYPE(o)->tp_name); - goto err; + if (!PyUnicode_FSConverter(o, &path->bytes)) { + path->object = path->bytes = NULL; + return 0; + } + path->path = PyBytes_AS_STRING(path->bytes); + path->length = PyBytes_GET_SIZE(path->bytes); } - - length = PyBytes_GET_SIZE(bytes); - tmp = PyBytes_AS_STRING(bytes); - if ((size_t)length != strlen(tmp)) { - PyErr_SetString(PyExc_TypeError, - "path has embedded nul character"); - goto err; - } - - path->path = tmp; - if (bytes == o) - Py_DECREF(bytes); - else - path->cleanup = bytes; - path->fd = -1; - -out: - path->length = length; + Py_INCREF(o); path->object = o; return Py_CLEANUP_SUPPORTED; - -err: - Py_XDECREF(o); - Py_XDECREF(bytes); - return 0; } PyObject *list_from_uint64_array(const uint64_t *arr, size_t n) @@ -150,8 +113,8 @@ PyObject *list_from_uint64_array(const uint64_t *arr, size_t n) void path_cleanup(struct path_arg *path) { + Py_CLEAR(path->bytes); Py_CLEAR(path->object); - Py_CLEAR(path->cleanup); } static PyMethodDef btrfsutil_methods[] = {