Control: Severity -1 serious
Control: Tags -1 patch
Hi,
This is still failing today. I'm not sure why the severity was reported
as important and not serious, i386 is still a release architecture.
From
https://buildd.debian.org/status/fetch.php?pkg=tinyarray&arch=i386&ver=1.2.5-1&stamp=1766523209&raw=0
This is the current cause of failure:
=================================== FAILURES
===================================
______________________________ test_hash_equality
______________________________
def test_hash_equality():
random.seed(123)
# These refer to the width of integers stored in a
tinyarray.ndarray_int.
int_bits = (8 * ta.dtype_size[int]) - 1 # 8 bits per byte,
minus 1 sign bit
maxint = 2**(int_bits)
special = [float('inf'), float('-inf'),
0, -1, -1.0, -1 + 0j,
303, -312424, -0.3, 1.7, 0.4j, -12.3j, 1 - 12.3j, 1.3
- 12.3j,
(), (-1,), (2,),
(0, 0), (-1, -1), (-5, 7), (3, -1, 0),
((0, 1), (2, 3)), (((-1,),),)]
powers = [sign * (2**e + a) for sign in [1, -1] for a in [-1, 0,
1]
for e in range(int_bits)]
powers.extend([2**int_bits - 1, -2**int_bits, -2**int_bits + 1])
small_random_ints = (random.randrange(-2**16, 2**16) for i in
range(1000))
large_random_ints = (random.randrange(-maxint, maxint) for i in
range(1000))
small_random_floats = (random.gauss(0, 1) for i in range(1000))
large_random_floats = (random.gauss(0, 1e100) for i in
range(1000))
for collection in [special, powers,
small_random_ints, large_random_ints,
small_random_floats, large_random_floats]:
for thing in collection:
arr = ta.array(thing)
if thing == thing:
assert arr == thing
assert not (arr != thing)
assert hash(arr) == hash(thing), repr(thing)
E AssertionError: -2147483648
E assert 1 == -2
E + where 1 = hash(array(-2147483648))
E + and -2 = hash(-2147483648)
../../../test_tinyarray.py:358: AssertionError
This happens because the code that calculates the hash overflows in
32bits with that number. It can be fixed by doing the calculation using
unsigned long instead. Attaching a patch here.
I'm working on an upload to solve this issue as well as #1146590
(failure on arm64 and other arches)
--
Regards,
Marga
Description: Fix integer hash calculation for minimum signed value
In 32bit architectures, using Py_hash_t for the sign and result variables
leads to overflows when x is LONG_MIN, that cause the hash to evaluate
incorrectly. So we cast to unsigned long to avoid the overflow.
Author: Maximiliano Curia <[email protected]>
--- a/src/array.cc
+++ b/src/array.cc
@@ -819,9 +819,10 @@
{
// For integers the hash is just the integer itself modulo _PyHASH_MODULUS
// except for the singular case of -1.
- // define 'sign' of the correct width to avoid overflow
- Py_hash_t sign = x < 0 ? -1 : 1;
- Py_hash_t result = sign * ((sign * x) % _PyHASH_MODULUS);
+ // Take the absolute value as unsigned long to avoid overflows when checking the sign.
+ unsigned long abs_x = x < 0 ? -static_cast<unsigned long>(x) : static_cast<unsigned long>(x);
+ Py_hash_t result = static_cast<Py_hash_t>(abs_x % _PyHASH_MODULUS);
+ if (x < 0) result = -result;
return result == -1 ? -2 : result;
}