Patch for PyStr regression on big-endian architectures
This commit is contained in:
parent
bcfbf082b2
commit
804fc1ddf2
2 changed files with 184 additions and 0 deletions
175
9c33ff9df61b3b9d71527acf4fb60a735d841025.patch
Normal file
175
9c33ff9df61b3b9d71527acf4fb60a735d841025.patch
Normal file
|
|
@ -0,0 +1,175 @@
|
|||
From 9c33ff9df61b3b9d71527acf4fb60a735d841025 Mon Sep 17 00:00:00 2001
|
||||
From: ijl <ijl@mailbox.org>
|
||||
Date: Wed, 23 Jul 2025 13:49:55 +0000
|
||||
Subject: [PATCH] Fix big-endian PyStr
|
||||
|
||||
---
|
||||
.github/workflows/artifact.yaml | 29 ++++++++++++++++
|
||||
README.md | 5 +--
|
||||
src/str/pystr.rs | 61 +++++++++++++++++++++------------
|
||||
3 files changed, 72 insertions(+), 23 deletions(-)
|
||||
|
||||
diff --git a/.github/workflows/artifact.yaml b/.github/workflows/artifact.yaml
|
||||
index fa628c03..d7283562 100644
|
||||
--- a/.github/workflows/artifact.yaml
|
||||
+++ b/.github/workflows/artifact.yaml
|
||||
@@ -269,6 +269,35 @@ jobs:
|
||||
if-no-files-found: "error"
|
||||
compression-level: 0
|
||||
|
||||
+ - name: setup-qemu-container
|
||||
+ if: "matrix.target.arch == 's390x'"
|
||||
+ uses: sandervocke/setup-qemu-container@v1
|
||||
+ with:
|
||||
+ container: registry.fedoraproject.org/fedora:42
|
||||
+ arch: ${{ matrix.target.arch }}
|
||||
+ podman_args: "-v .:/orjson -v /tmp:/tmp --workdir /orjson"
|
||||
+
|
||||
+ - name: setup-shell-wrapper
|
||||
+ uses: sandervocke/setup-shell-wrapper@v1
|
||||
+
|
||||
+ - name: Emulated Test
|
||||
+ if: "matrix.target.arch == 's390x'"
|
||||
+ shell: wrap-shell {0}
|
||||
+ env:
|
||||
+ WRAP_SHELL: run-in-container.sh
|
||||
+ run: |
|
||||
+ set -eou pipefail
|
||||
+
|
||||
+ dnf install --setopt=install_weak_deps=false -y ${{ matrix.python.interpreter }} python3-uv
|
||||
+
|
||||
+ uv venv --python ${{ matrix.python.interpreter }}
|
||||
+ source .venv/bin/activate
|
||||
+
|
||||
+ uv pip install -r test/requirements.txt
|
||||
+ uv pip install dist/orjson*.whl
|
||||
+
|
||||
+ pytest -v test
|
||||
+
|
||||
musllinux_amd64:
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 10
|
||||
diff --git a/README.md b/README.md
|
||||
index f0b9a6a0..3b7b642f 100644
|
||||
--- a/README.md
|
||||
+++ b/README.md
|
||||
@@ -1088,8 +1088,9 @@ is prudent to pin the nightly version because that channel can introduce
|
||||
breaking changes. There is a significant performance benefit to using
|
||||
nightly.
|
||||
|
||||
-orjson is tested for amd64, aarch64, and i686 on Linux and cross-compiles for
|
||||
-arm7, ppc64le, and s390x. It is tested for either aarch64 or amd64 on macOS and
|
||||
+orjson is tested on native hardware for amd64, aarch64, and i686 on Linux and
|
||||
+for arm7, ppc64le, and s390x is cross-compiled and may be tested via
|
||||
+emulation. It is tested for either aarch64 or amd64 on macOS and
|
||||
cross-compiles for the other, depending on version. For Windows it is
|
||||
tested on amd64 and i686.
|
||||
|
||||
diff --git a/src/str/pystr.rs b/src/str/pystr.rs
|
||||
index a856b13a..186a0e50 100644
|
||||
--- a/src/str/pystr.rs
|
||||
+++ b/src/str/pystr.rs
|
||||
@@ -1,11 +1,14 @@
|
||||
// SPDX-License-Identifier: (Apache-2.0 OR MIT)
|
||||
|
||||
use crate::typeref::{EMPTY_UNICODE, STR_TYPE};
|
||||
+#[cfg(target_endian = "little")]
|
||||
use crate::util::isize_to_usize;
|
||||
-
|
||||
+#[cfg(target_endian = "little")]
|
||||
use core::ffi::c_void;
|
||||
use core::ptr::NonNull;
|
||||
-use pyo3_ffi::{PyASCIIObject, PyCompactUnicodeObject, PyObject};
|
||||
+#[cfg(target_endian = "little")]
|
||||
+use pyo3_ffi::PyCompactUnicodeObject;
|
||||
+use pyo3_ffi::{PyASCIIObject, PyObject};
|
||||
|
||||
fn to_str_via_ffi(op: *mut PyObject) -> Option<&'static str> {
|
||||
let mut str_size: pyo3_ffi::Py_ssize_t = 0;
|
||||
@@ -32,29 +35,21 @@ pub fn set_str_create_fn() {
|
||||
}
|
||||
}
|
||||
|
||||
-#[cfg(all(Py_3_14, Py_GIL_DISABLED))]
|
||||
-const STATE_COMPACT_ASCII: u32 = u32::from_le(0b000000000000000000_0_1_1_001_00000000);
|
||||
-
|
||||
-#[cfg(not(all(Py_3_14, Py_GIL_DISABLED)))]
|
||||
-const STATE_COMPACT_ASCII: u32 = u32::from_le(0b000000000000000000000000_0_1_1_001_00);
|
||||
-
|
||||
-#[cfg(all(Py_3_14, Py_GIL_DISABLED))]
|
||||
-const STATE_COMPACT: u32 = u32::from_le(0b000000000000000000_0_0_1_000_00000000);
|
||||
-
|
||||
-#[cfg(not(all(Py_3_14, Py_GIL_DISABLED)))]
|
||||
-const STATE_COMPACT: u32 = u32::from_le(0b000000000000000000000000_0_0_1_000_00);
|
||||
+#[cfg(all(target_endian = "little", Py_3_14, Py_GIL_DISABLED))]
|
||||
+const STATE_KIND_SHIFT: usize = 8;
|
||||
|
||||
-#[cfg(all(Py_3_14, Py_GIL_DISABLED))]
|
||||
-const STATE_KIND_MASK: u32 = u32::from_le(0b111_00000000);
|
||||
+#[cfg(all(target_endian = "little", not(all(Py_3_14, Py_GIL_DISABLED))))]
|
||||
+const STATE_KIND_SHIFT: usize = 2;
|
||||
|
||||
-#[cfg(all(Py_3_14, Py_GIL_DISABLED))]
|
||||
-const STATE_KIND_SHIFT: usize = 8;
|
||||
+#[cfg(target_endian = "little")]
|
||||
+const STATE_KIND_MASK: u32 = 7 << STATE_KIND_SHIFT;
|
||||
|
||||
-#[cfg(not(all(Py_3_14, Py_GIL_DISABLED)))]
|
||||
-const STATE_KIND_MASK: u32 = u32::from_le(0b111_00);
|
||||
+#[cfg(target_endian = "little")]
|
||||
+const STATE_COMPACT_ASCII: u32 =
|
||||
+ 1 << STATE_KIND_SHIFT | 1 << (STATE_KIND_SHIFT + 3) | 1 << (STATE_KIND_SHIFT + 4);
|
||||
|
||||
-#[cfg(not(all(Py_3_14, Py_GIL_DISABLED)))]
|
||||
-const STATE_KIND_SHIFT: usize = 2;
|
||||
+#[cfg(target_endian = "little")]
|
||||
+const STATE_COMPACT: u32 = 1 << (STATE_KIND_SHIFT + 3);
|
||||
|
||||
#[repr(transparent)]
|
||||
#[derive(Copy, Clone)]
|
||||
@@ -96,6 +91,7 @@ impl PyStr {
|
||||
}
|
||||
}
|
||||
|
||||
+ #[cfg(target_endian = "little")]
|
||||
pub fn hash(&mut self) {
|
||||
unsafe {
|
||||
let ptr = self.ptr.as_ptr().cast::<PyASCIIObject>();
|
||||
@@ -118,7 +114,24 @@ impl PyStr {
|
||||
}
|
||||
}
|
||||
|
||||
+ #[cfg(not(target_endian = "little"))]
|
||||
+ pub fn hash(&mut self) {
|
||||
+ unsafe {
|
||||
+ let data_ptr = ffi!(PyUnicode_DATA(self.ptr.as_ptr()));
|
||||
+ #[allow(clippy::cast_possible_wrap)]
|
||||
+ let num_bytes =
|
||||
+ ffi!(PyUnicode_KIND(self.ptr.as_ptr())) as isize * ffi!(Py_SIZE(self.ptr.as_ptr()));
|
||||
+ #[cfg(Py_3_14)]
|
||||
+ let hash = pyo3_ffi::Py_HashBuffer(data_ptr, num_bytes);
|
||||
+ #[cfg(not(Py_3_14))]
|
||||
+ let hash = pyo3_ffi::_Py_HashBytes(data_ptr, num_bytes);
|
||||
+ (*self.ptr.as_ptr().cast::<PyASCIIObject>()).hash = hash;
|
||||
+ debug_assert!((*self.ptr.as_ptr().cast::<PyASCIIObject>()).hash != -1);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
#[inline(always)]
|
||||
+ #[cfg(target_endian = "little")]
|
||||
pub fn to_str(self) -> Option<&'static str> {
|
||||
unsafe {
|
||||
let op = self.ptr.as_ptr();
|
||||
@@ -140,6 +153,12 @@ impl PyStr {
|
||||
}
|
||||
}
|
||||
|
||||
+ #[inline(always)]
|
||||
+ #[cfg(not(target_endian = "little"))]
|
||||
+ pub fn to_str(self) -> Option<&'static str> {
|
||||
+ to_str_via_ffi(self.ptr.as_ptr())
|
||||
+ }
|
||||
+
|
||||
pub fn as_ptr(self) -> *mut PyObject {
|
||||
self.ptr.as_ptr()
|
||||
}
|
||||
|
|
@ -64,6 +64,15 @@ Source0: orjson-%{version}-filtered.tar.xz
|
|||
# ./get_source ${COMMIT} (or ${TAG})
|
||||
Source1: get_source
|
||||
|
||||
# Fix big-endian PyStr
|
||||
# https://github.com/ijl/orjson/commit/9c33ff9df61b3b9d71527acf4fb60a735d841025
|
||||
#
|
||||
# Fixes:
|
||||
#
|
||||
# Test regressions (segfaults) on s390x architecture in 3.11.0
|
||||
# https://github.com/ijl/orjson/issues/584
|
||||
Patch: %{url}/commit/9c33ff9df61b3b9d71527acf4fb60a735d841025.patch
|
||||
|
||||
BuildRequires: tomcli
|
||||
BuildRequires: python3-devel
|
||||
BuildRequires: %{py3_dist pytest-forked}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue