From ea202df0dc04663fa6c5f00200a4d6855798bd89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20Tornar=C3=ADa?= Date: Wed, 14 Dec 2022 10:51:34 -0300 Subject: [PATCH] sagemath: fix for 32 bit architectures After the upgrade to python 3.11, sagemath is completely broken (it won't even start). See: https://trac.sagemath.org/ticket/33842#comment:130 This revbump adds a fix taken from that trac ticket (https://trac.sagemath.org/ticket/33842#comment:137) --- .../trac-33842-04-python3.11_fix_32_bit.patch | 212 ++++++++++++++++++ srcpkgs/sagemath/template | 2 +- 2 files changed, 213 insertions(+), 1 deletion(-) create mode 100644 srcpkgs/sagemath/patches/trac-33842-04-python3.11_fix_32_bit.patch diff --git a/srcpkgs/sagemath/patches/trac-33842-04-python3.11_fix_32_bit.patch b/srcpkgs/sagemath/patches/trac-33842-04-python3.11_fix_32_bit.patch new file mode 100644 index 000000000000..4c26dfdb6843 --- /dev/null +++ b/srcpkgs/sagemath/patches/trac-33842-04-python3.11_fix_32_bit.patch @@ -0,0 +1,212 @@ +diff --git a/src/sage/arith/long.pxd b/src/sage/arith/long.pxd +index b0c80f61480..1c9a53387a0 100644 +--- a/src/sage/arith/long.pxd ++++ b/src/sage/arith/long.pxd +@@ -124,7 +124,7 @@ cdef inline bint integer_check_long(x, long* value, int* err) except -1: + ....: if err == 0: + ....: return value + ....: elif err == ERR_OVERFLOW: +- ....: raise OverflowError("integer_check_long: overflow") ++ ....: raise OverflowError(f"integer_check_long: overflow ({x})") + ....: elif err == ERR_TYPE: + ....: raise TypeError("integer_check_long: wrong type") + ....: elif err == ERR_INDEX: +@@ -136,24 +136,23 @@ cdef inline bint integer_check_long(x, long* value, int* err) except -1: + ....: def long_max(): + ....: return smallInteger(LONG_MAX) + ....: ''') +- sage: types = (ZZ, QQ, int) + sage: L = [1, 12345, 10^9, 2^30, long_max()//9, long_max()//3, long_max()] + sage: L += [-x for x in L] + [0, long_min()] + sage: for v in L: +- ....: for t in (Integer, int): ++ ....: for t in (Integer, int, QQ): + ....: assert check_long(t(v)) == v + sage: check_long(2^100) + Traceback (most recent call last): + ... +- OverflowError: integer_check_long: overflow ++ OverflowError: integer_check_long: overflow (...) + sage: check_long(long_max() + 1) + Traceback (most recent call last): + ... +- OverflowError: integer_check_long: overflow ++ OverflowError: integer_check_long: overflow (...) + sage: check_long(long_min() - 1) + Traceback (most recent call last): + ... +- OverflowError: integer_check_long: overflow ++ OverflowError: integer_check_long: overflow (...) + sage: check_long("hello") + Traceback (most recent call last): + ... +@@ -162,6 +161,36 @@ cdef inline bint integer_check_long(x, long* value, int* err) except -1: + Traceback (most recent call last): + ... + TypeError: integer_check_long: bad __index__ ++ ++ Repeat the overflow tests with python integers: ++ ++ sage: check_long(int(2^100)) ++ Traceback (most recent call last): ++ ... ++ OverflowError: integer_check_long: overflow (...) ++ sage: check_long(int(long_max() + 1)) ++ Traceback (most recent call last): ++ ... ++ OverflowError: integer_check_long: overflow (...) ++ sage: check_long(int(long_min() - 1)) ++ Traceback (most recent call last): ++ ... ++ OverflowError: integer_check_long: overflow (...) ++ ++ And again with rationals: ++ ++ sage: check_long(QQ(2^100)) ++ Traceback (most recent call last): ++ ... ++ OverflowError: integer_check_long: overflow (...) ++ sage: check_long(QQ(long_max() + 1)) ++ Traceback (most recent call last): ++ ... ++ OverflowError: integer_check_long: overflow (...) ++ sage: check_long(QQ(long_min() - 1)) ++ Traceback (most recent call last): ++ ... ++ OverflowError: integer_check_long: overflow (...) + """ + cdef int c = integer_check_long_py(x, value, err) + if c: +@@ -193,35 +222,93 @@ cdef inline long dig(const digit* D, int n): + + cdef inline bint integer_check_long_py(x, long* value, int* err): + """ +- Part of ``integer_check_long`` in ``long.pxd``, checking only for +- Python objects of type ``int`` and ``long``. See that function for +- documentation and tests. ++ Return whether ``x`` is a python object of type ``int``. ++ ++ If possible, compute the value of this integer as C long and store ++ it in ``*value``. ++ ++ Errors are returned as an error indicator ``*err`` (without raising ++ any Python exception). ++ ++ Possible errors when returning ``True``: ++ ++ - ``0``: ``x`` was successfully converted to a C long and its value ++ is stored in ``*value``. ++ ++ - ``ERR_OVERFLOW``: ``x`` is a python object of type ``int`` but ++ too large to store in a C long. ++ ++ Possible errors when returning ``False``: ++ ++ - ``ERR_TYPE``: ``x`` is not a python object of type ``int``. ++ ++ EXAMPLES: ++ ++ We create a pure Python wrapper of this function:: ++ ++ sage: cython(''' # optional - sage.misc.cython ++ ....: from sage.arith.long cimport * ++ ....: def check_long_py(x): ++ ....: cdef long value ++ ....: cdef int err ++ ....: cdef bint c = integer_check_long_py(x, &value, &err) ++ ....: if c: ++ ....: if err == 0: ++ ....: return value ++ ....: elif err == ERR_OVERFLOW: ++ ....: return f"Overflow ({x})" ++ ....: elif err == ERR_TYPE: ++ ....: return f"Bad type ({x})" ++ ....: return f"This should never happen ({x})" ++ ....: from libc.limits cimport LONG_MIN, LONG_MAX ++ ....: def long_min(): ++ ....: return LONG_MIN ++ ....: def long_max(): ++ ....: return LONG_MAX ++ ....: ''') ++ sage: L = [1, 12345, 10^9, 2^30, long_max()//9, long_max()//3, long_max()] ++ sage: L += [-x for x in L] + [0, long_min()] ++ sage: for v in L: ++ ....: assert check_long_py(int(v)) == v ++ sage: check_long_py(int(2^100)) ++ 'Overflow (...)' ++ sage: check_long_py(int(long_max() + 1)) ++ 'Overflow (...)' ++ sage: check_long_py(int(long_min() - 1)) ++ 'Overflow (...)' ++ sage: check_long_py(389) ++ 'Bad type (...)' ++ sage: check_long_py("hello") ++ 'Bad type (...)' ++ sage: check_long_py(2/3) ++ 'Bad type (...)' + """ +- if not isinstance(x, long): +- if isinstance(x, int): +- # This can happen only on Python 2 +- value[0] = PyInt_AS_LONG(x) +- err[0] = 0 +- return 1 ++ if not isinstance(x, int): + err[0] = ERR_TYPE + return 0 + +- # x is a Python "long" (called "int" on Python 3) ++ # x is a Python "int" (aka PyLongObject or py_long in cython) + cdef const digit* D = (x).ob_digit + cdef Py_ssize_t size = Py_SIZE(x) + +- # We assume that PyLong_SHIFT is 15 on a 32-bit system and 30 on a +- # 64-bit system. This is not guaranteed by Python, but it is the +- # default configuration. ++ # We assume PyLong_SHIFT <= BITS_IN_LONG <= 3 * PyLong_SHIFT. ++ # This is true in all the default configurations: ++ # - BITS_IN_LONG = 63, PyLong_SHIFT = 30 ++ # - BITS_IN_LONG = 31, PyLong_SHIFT = 15 (python <= 3.10) ++ # - BITS_IN_LONG = 31, PyLong_SHIFT = 30 (new in python 3.11) ++ # cf. https://trac.sagemath.org/ticket/33842#comment:130 + # +- # This way, we know that 1 and 2 digits certainly fit in a C long +- # and 4 or more digits never fit. For 3 digits, we need an explicit +- # overflow check. ++ # This way, we know that 1 digit certainly fits in a C long ++ # and 4 or more digits never fit. ++ # For 2 or 3 digits, we need an explicit overflow check. + cdef int BITS_IN_LONG = 8 * sizeof(long) - 1 +- if not (2 * PyLong_SHIFT <= BITS_IN_LONG < 4 * PyLong_SHIFT): +- raise AssertionError ++ if not (PyLong_SHIFT <= BITS_IN_LONG <= 3 * PyLong_SHIFT): ++ raise AssertionError( ++ f"PyLong_SHIFT = {PyLong_SHIFT}, " ++ f"BITS_IN_LONG = {BITS_IN_LONG}") + + cdef long lead ++ cdef long lead_2_overflow = (1) << (BITS_IN_LONG - PyLong_SHIFT) + cdef long lead_3_overflow = (1) << (BITS_IN_LONG - 2 * PyLong_SHIFT) + if size == 0: + value[0] = 0 +@@ -233,9 +320,20 @@ cdef inline bint integer_check_long_py(x, long* value, int* err): + value[0] = -dig(D, 0) + err[0] = 0 + elif size == 2: ++ if BITS_IN_LONG < 2 * PyLong_SHIFT and D[1] >= lead_2_overflow: ++ err[0] = ERR_OVERFLOW ++ return 1 + value[0] = dig(D, 0) + dig(D, 1) + err[0] = 0 + elif size == -2: ++ if BITS_IN_LONG < 2 * PyLong_SHIFT and D[1] >= lead_2_overflow: ++ if D[0] == 0 and D[1] == lead_2_overflow: ++ # Special case for LONG_MIN ++ value[0] = (-1) << BITS_IN_LONG ++ err[0] = 0 ++ else: ++ err[0] = ERR_OVERFLOW ++ return 1 + value[0] = -(dig(D, 0) + dig(D, 1)) + err[0] = 0 + elif size == 3: diff --git a/srcpkgs/sagemath/template b/srcpkgs/sagemath/template index 0cc79bda923b..74445c3aa8c1 100644 --- a/srcpkgs/sagemath/template +++ b/srcpkgs/sagemath/template @@ -1,7 +1,7 @@ # Template file for 'sagemath' pkgname=sagemath version=9.7 -revision=3 +revision=4 build_wrksrc=pkgs/sagemath-standard build_style=python3-module _bindir=/usr/lib/sagemath/$version/bin