ijl / orjson

Fast, correct Python JSON library supporting dataclasses, datetimes, and numpy
Apache License 2.0
6.29k stars 215 forks source link

Path to using published versions of pyo3-ffi/pyo3-build-config again? #524

Closed musicinmybrain closed 1 month ago

musicinmybrain commented 1 month ago

In c5af268e4c48743d4959c6ddd676a93a5397f108, the pyo3-ffi and pyo3-build-config crates were vendored. The commit message does not explain why, but it appears that this was done in order to support alpha releases of Python 3.14.

Fedora’s packaging guidelines require me to inquire about a path back to supporting system versions of these libraries, i.e., using released crates rather than vendored ones.

I also wonder if it is wise to use arbitrary unreleased development snapshots for FFI – not just on Python 3.14, but for all Python versions – in a library that is very likely to be used for processing untrusted data. I doubt that the PyO3 developers expect such snapshots to be used in production.

A similar past issue was https://github.com/ijl/orjson/issues/373.

@gotmax23 @decathorpe

ijl commented 1 month ago

You are welcome to work to upstream the diff if you find the vendoring unsuitable for your organization's own preferences.

This is the diff against pyo3@dc415fae9f5eaa8ac0f6d0ea769b9ab28860898f

diff --git a/pyo3-build-config/src/lib.rs b/pyo3-build-config/src/lib.rs
index 033e7b46..6e295c99 100644
--- a/pyo3-build-config/src/lib.rs
+++ b/pyo3-build-config/src/lib.rs
@@ -181,6 +181,7 @@ pub fn print_expected_cfgs() {
     for i in impl_::MINIMUM_SUPPORTED_VERSION.minor..=impl_::ABI3_MAX_MINOR + 1 {
         println!("cargo:rustc-check-cfg=cfg(Py_3_{i})");
     }
+    println!("cargo::rustc-check-cfg=cfg(Py_3_14)");
 }

 /// Private exports used in PyO3's build.rs
diff --git a/pyo3-ffi/src/cpython/lock.rs b/pyo3-ffi/src/cpython/lock.rs
index 6c80b00d..c451666e 100644
--- a/pyo3-ffi/src/cpython/lock.rs
+++ b/pyo3-ffi/src/cpython/lock.rs
@@ -8,6 +8,15 @@ pub struct PyMutex {
     pub(crate) _pin: PhantomPinned,
 }

+impl PyMutex {
+    pub const fn new() -> PyMutex {
+        PyMutex {
+            _bits: AtomicU8::new(0),
+            _pin: PhantomPinned,
+        }
+    }
+}
+
 extern "C" {
     pub fn PyMutex_Lock(m: *mut PyMutex);
     pub fn PyMutex_Unlock(m: *mut PyMutex);
diff --git a/pyo3-ffi/src/methodobject.rs b/pyo3-ffi/src/methodobject.rs
index 3dfbbb5a..bd214409 100644
--- a/pyo3-ffi/src/methodobject.rs
+++ b/pyo3-ffi/src/methodobject.rs
@@ -68,7 +68,6 @@ pub type PyCFunctionFastWithKeywords = unsafe extern "C" fn(
 ) -> *mut PyObject;

 #[cfg(any(Py_3_10, not(Py_LIMITED_API)))]
-#[deprecated(note = "renamed to `PyCFunctionFastWithKeywords`")]
 pub type _PyCFunctionFastWithKeywords = PyCFunctionFastWithKeywords;

 #[cfg(all(Py_3_9, not(Py_LIMITED_API)))]
@@ -162,7 +161,6 @@ pub union PyMethodDefPointer {

     /// This variant corresponds with [`METH_FASTCALL`] | [`METH_KEYWORDS`].
     #[cfg(any(Py_3_10, not(Py_LIMITED_API)))]
-    #[deprecated(note = "renamed to `PyCFunctionFastWithKeywords`")]
     pub _PyCFunctionFastWithKeywords: PyCFunctionFastWithKeywords,

     /// This variant corresponds with [`METH_FASTCALL`] | [`METH_KEYWORDS`].
diff --git a/pyo3-ffi/src/modsupport.rs b/pyo3-ffi/src/modsupport.rs
index 4a18d30f..6da2795b 100644
--- a/pyo3-ffi/src/modsupport.rs
+++ b/pyo3-ffi/src/modsupport.rs
@@ -36,6 +36,13 @@ extern "C" {
     pub fn Py_BuildValue(arg1: *const c_char, ...) -> *mut PyObject;
     // skipped Py_VaBuildValue

+    #[cfg(Py_3_13)]
+    pub fn PyModule_Add(
+        module: *mut PyObject,
+        name: *const c_char,
+        value: *mut PyObject,
+    ) -> core::ffi::c_int;
+
     #[cfg(Py_3_10)]
     #[cfg_attr(PyPy, link_name = "PyPyModule_AddObjectRef")]
     pub fn PyModule_AddObjectRef(
diff --git a/pyo3-ffi/src/object.rs b/pyo3-ffi/src/object.rs
index fc3484be..d2fa1930 100644
--- a/pyo3-ffi/src/object.rs
+++ b/pyo3-ffi/src/object.rs
@@ -211,7 +211,7 @@ pub unsafe fn Py_SIZE(ob: *mut PyObject) -> Py_ssize_t {

 #[inline(always)]
 #[cfg(all(Py_3_12, not(Py_GIL_DISABLED)))]
-unsafe fn _Py_IsImmortal(op: *mut PyObject) -> c_int {
+pub unsafe fn _Py_IsImmortal(op: *mut PyObject) -> c_int {
     #[cfg(target_pointer_width = "64")]
     {
         (((*op).ob_refcnt.ob_refcnt as crate::PY_INT32_T) < 0) as c_int
diff --git a/pyo3-ffi/src/pyhash.rs b/pyo3-ffi/src/pyhash.rs
index f42f9730..19459903 100644
--- a/pyo3-ffi/src/pyhash.rs
+++ b/pyo3-ffi/src/pyhash.rs
@@ -10,8 +10,11 @@ extern "C" {
     // skipped non-limited _Py_HashPointer
     // skipped non-limited _Py_HashPointerRaw

-    #[cfg(not(any(Py_LIMITED_API, PyPy, GraalPy)))]
+    #[cfg(not(all(Py_3_14, any(Py_LIMITED_API, PyPy, GraalPy))))]
     pub fn _Py_HashBytes(src: *const c_void, len: Py_ssize_t) -> Py_hash_t;
+
+    #[cfg(Py_3_14)]
+    pub fn Py_HashBuffer(ptr: *const c_void, len: Py_ssize_t) -> Py_hash_t;
 }

 pub const _PyHASH_MULTIPLIER: c_ulong = 1000003;

You'll notice PyMutex::new() needs to be public for 3.13+ freethreading using only pyo-ffi, _PyCFunctionFastWithKeywords was deprecated at the wrong version, _Py_IsImmortal() was made private to pyo3-ffi, PyModule_Add() is optional, and Py_HashBuffer() is 3.14 compatibility.