python3.14-numpy/fix-signed-overflow-s390x.patch
Charalampos Stratakis 2677b5a6f2 Fix signed overflow issue in npy_gcd for INT_MIN on s390x
Resolves: RHEL-193000
2026-08-13 15:44:15 +02:00

71 lines
3.1 KiB
Diff

From 80071371601233408b4d919dfe7cc05cfee93d02 Mon Sep 17 00:00:00 2001
From: AnkitAhlawat <Ankit.Ahlawat@ibm.com>
Date: Thu, 30 Apr 2026 19:18:10 +0530
Subject: [PATCH] BUG: Fix signed overflow issue in npy_gcd for INT_MIN on
s390x (#31360)
This PR fixes signed overflow issue in npy_gcd when one of the inputs is the minimum value of a signed integer type (INT_MIN) on s390x architecture.
issue was the expression a < 0 ? -a : a in npy_math_internal.h.src causes undefined behavior when a = INT_MIN because negating INT_MIN overflows a signed integer on s390x. i see it is working fine with other arch so fix only provided to s390x
---
numpy/_core/src/npymath/npy_math_internal.h.src | 11 ++++++++++-
numpy/_core/tests/test_umath.py | 12 ++++++++----
2 files changed, 18 insertions(+), 5 deletions(-)
diff --git a/numpy/_core/src/npymath/npy_math_internal.h.src b/numpy/_core/src/npymath/npy_math_internal.h.src
index 2f38497..787f7e6 100644
--- a/numpy/_core/src/npymath/npy_math_internal.h.src
+++ b/numpy/_core/src/npymath/npy_math_internal.h.src
@@ -650,12 +650,21 @@ npy_lcm@c@(@type@ a, @type@ b)
*
* #type = (npy_int, npy_long, npy_longlong)*2#
* #c = (,l,ll)*2#
+ * #utype = (npy_uint, npy_ulong, npy_ulonglong)*2#
* #func=gcd*3,lcm*3#
*/
NPY_INPLACE @type@
npy_@func@@c@(@type@ a, @type@ b)
{
- return npy_@func@u@c@(a < 0 ? -a : a, b < 0 ? -b : b);
+ /*
+ * Cast to unsigned to avoid overflow when negating minimum signed value.
+ * For negative values, cast to unsigned first, then apply negation in
+ * unsigned arithmetic to avoid undefined behavior.
+ * This ensures correct behavior across all architectures. #31359
+ */
+ @utype@ a_abs = a < 0 ? (@utype@)(0) - (@utype@)a : (@utype@)a;
+ @utype@ b_abs = b < 0 ? (@utype@)(0) - (@utype@)b : (@utype@)b;
+ return (@type@)npy_@func@u@c@(a_abs, b_abs);
}
/**end repeat**/
diff --git a/numpy/_core/tests/test_umath.py b/numpy/_core/tests/test_umath.py
index 8eac236..1575dd6 100644
--- a/numpy/_core/tests/test_umath.py
+++ b/numpy/_core/tests/test_umath.py
@@ -4131,13 +4131,17 @@ def test_lcm_overflow(self):
assert_equal(np.lcm(a, b), 10 * big)
def test_gcd_overflow(self):
- for dtype in (np.int32, np.int64):
- # verify that we don't overflow when taking abs(x)
- # not relevant for lcm, where the result is unrepresentable anyway
- a = dtype(np.iinfo(dtype).min) # negative power of two
+ # verify that we don't overflow when taking abs(x) for INT_MIN
+ # this was undefined behavior that manifested on s390x with GCC 11.5
+ for dtype in (np.int8, np.int16, np.int32, np.int64):
+ a = dtype(np.iinfo(dtype).min) # INT_MIN
q = -(a // 4)
+ # Test with INT_MIN as first argument
assert_equal(np.gcd(a, q * 3), q)
assert_equal(np.gcd(a, -q * 3), q)
+ # Test with INT_MIN as second argument
+ assert_equal(np.gcd(q * 3, a), q)
+ assert_equal(np.gcd(-q * 3, a), q)
def test_decimal(self):
from decimal import Decimal
--
2.54.0