Package: src:tinyarray
Version: 1.2.5-1
User: [email protected]
Usertags: python3.15
Tags: patch, ftbfs, forky, sid

Hi!

While rebuilding the python related packages against the Python 3.15rc1
version we found that tinyarray fails to build from source on arm64 [1].
This also fails on Debian's buildds [2].

It fails in arm64 with: Failed: DID NOT RAISE OverflowError

When converting floats to integer, `std::numeric_limits<long>::max()`
(2^63 - 1) rounds up to 2^63 in float/double, causing `*ptr > max()` to
be false for 2^63. The subsequent check on the cast integer relied on
architecture-specific overflow behavior that does not hold on ARM64
(where out-of-range floats saturate to positive INT64_MAX instead of
negative values).

So, to fix it, check bounds against exact power-of-two limits before
casting to detect  overflow portably across architectures.

I applied the fix in the sandbox [3] to be able to build the packages
that depend on tinyarray, please consider applying the patch to support
the upcoming 3.15 version.

Happy hacking,

[1]: https://debusine.debian.net/debian/r-python-python3.15/artifact/4316397/
[2]: 
https://buildd.debian.org/status/fetch.php?pkg=tinyarray&arch=arm64&ver=1.2.5-1&stamp=1766523038&raw=0
[3]: https://debusine.debian.net/debian/r-python-python3.15/

--
"Can you imagine what I would do if I could do all I can?" -- Sun Tzu
Saludos /\/\ /\ >< `/
Description: Fix float-to-integer overflow detection across architectures
 When converting floats to integer, std::numeric_limits<long>::max() (2^63 - 1)
 rounds up to 2^63 in float/double, causing *ptr > max() to be false for 2^63.
 The subsequent check on the cast integer relied on architecture-specific
 overflow behavior that does not hold on ARM64 (where out-of-range floats
 saturate to positive INT64_MAX instead of negative values).
 .
 Check bounds against exact power-of-two limits before casting to detect
 overflow portably across architectures.
Author: Maximiliano Curia <[email protected]>
diff --git a/src/conversion.hh b/src/conversion.hh
index bb7de89..7da9563 100644
--- a/src/conversion.hh
+++ b/src/conversion.hh
@@ -177,22 +177,18 @@ inline long number_from_ptr<long, unsigned long long>(const void *data)
 template<typename Tdest, typename Tsrc>
 inline Tdest _int_from_floatptr_exact(const void *data)
 {
-    const Tsrc *ptr = reinterpret_cast<const Tsrc*>(data);
-    Tdest result = static_cast<Tdest>(*ptr);
-
-    // Note: the > max and < min tests are unreliable since the floating point
-    // representation of the maximal/minimal value may not be exact. The two
-    // other tests catch these problems.  This approach looks flimsy and is
-    // implementation-dependent, but it is tested rigourosly.
-    if (*ptr > std::numeric_limits<Tdest>::max() ||
-        *ptr < std::numeric_limits<Tdest>::min() ||
-        (*ptr > 0 && result < 0) || (*ptr < 0 && result > 0)) {
+    const Tsrc val = *reinterpret_cast<const Tsrc*>(data);
+    const Tsrc min_val = static_cast<Tsrc>(std::numeric_limits<Tdest>::min());
+    const Tsrc max_val_plus_1 = -min_val;
+    const Tsrc min_minus_1 = min_val - static_cast<Tsrc>(1);
+    const bool underflow = (min_minus_1 < min_val) ? (val <= min_minus_1) : (val < min_val);
+
+    if (!(val < max_val_plus_1) || underflow) {
         PyErr_Format(PyExc_OverflowError,
                      "Float too large to be represented by long");
         return -1;
-    } else
-    {
-        return result;
+    } else {
+        return static_cast<Tdest>(val);
     }
 }
 

Reply via email to