Opened 3 months ago

Last modified 3 months ago

#34492 new enhancement

avoid crash and print better error message when gmp calls abort()

Reported by: Dave Morris Owned by:
Priority: minor Milestone: sage-9.8
Component: basic arithmetic Keywords: crash, gmp
Cc: Samuel Lelièvre, Paul Zimmermann Merged in:
Authors: Reviewers:
Report Upstream: N/A Work issues:
Branch: Commit:
Dependencies: Stopgaps:

Status badges

Description

gmp sometimes calls abort(). (For example,this StackOverflow post says "whenever you try to create or calculate a number with more than 231 - 1 limbs (or machine words), GMP will abort.") This can crash sage or result in cryptic error messages.

Unfortunately, it seems that gmp does not provide a good way to trap these errors to provide helpful OverFlow error messages. (See the discussions here and here.) So this may need an upstream fix. Jereon Demeyer suggested an approach that could fix this in 2017 on the gmp-discuss mailing list, but it seems that nothing came of it.

Even if we cannot improve the error messages, can we eliminate the crashes by using sig_on() / sig_off()?

This ticket came from a sage-devel discussion that includes the following two examples.

This crashes sage:

sage: def binnk3u(n,k):  return (n/k)**(k))
sage: n1=(2*10**3)
sage: d0=29004853178239
sage: n0=SR(log(n1))
sage: tt=binnk3u(n0+d0-1,(d0))
gmp: overflow in mpz type
------------------------------------------------------------------------
(no backtrace available)
------------------------------------------------------------------------
Unhandled SIGABRT: An abort() occurred.
This probably occurred because a *compiled* module has a bug
in it and is not properly wrapped with sig_on(), sig_off().
Python will now terminate.
------------------------------------------------------------------------
~/development/sage94/src/bin/sage-python: line 2: 55217 Abort trap: 6           sage -python "$@"

This should give a better error message:

sage: 2^(2^62)
gmp: overflow in mpz type
---------------------------------------------------------------------------
RuntimeError                              Traceback (most recent call last)
Input In [1], in <cell line: 1>()
----> 1 Integer(2)**(Integer(2)**Integer(62))

File ~/development/sage94/src/sage/rings/integer.pyx:2191, in sage.rings.integer.Integer.__pow__()
   2189 
   2190         if type(left) is type(right):
-> 2191             return (<Integer>left)._pow_(right)
   2192         elif isinstance(left, Element):
   2193             return coercion_model.bin_op(left, right, operator.pow)

File ~/development/sage94/src/sage/rings/integer.pyx:2255, in sage.rings.integer.Integer._pow_()
   2253 
   2254         if mpz_fits_slong_p(exp):
-> 2255             return self._pow_long(mpz_get_si(exp))
   2256 
   2257         # Raising to an exponent which doesn't fit in a long overflows

File ~/development/sage94/src/sage/rings/integer.pyx:2287, in sage.rings.integer.Integer._pow_long()
   2285 if n > 0:
   2286     x = PY_NEW(Integer)
-> 2287     sig_on()
   2288     mpz_pow_ui(x.value, self.value, n)
   2289     sig_off()

RuntimeError: Aborted

The message "gmp: overflow in mpz type" is printed to stderr, so some users might not see it, which would make the error messages even more cryptic.

Change History (4)

comment:1 Changed 3 months ago by Vincent Delecroix

The message "gmp: overflow in mpz type" is printed to
stderr, so some users might not see it, which would
make the error messages even more cryptic. 

It explains why the message appears at the beginning of the traceback! This is indeed documented and one solution could be to set up our own error callback with gmp custom allocation.

Last edited 3 months ago by Vincent Delecroix (previous) (diff)

comment:2 Changed 3 months ago by Dave Morris

According to the page you referenced, a gmp custom allocation must terminate execution (not just raise an exception), so there is a limit to what can be done, but it still might provide a solution, as you suggest.

"No error return is allowed from any of these functions, if they return then they must have performed the specified operation. In particular note that allocate_function or reallocate_function mustn’t return NULL.

Getting a different fatal error action is a good use for custom allocation functions, for example giving a graphical dialog rather than the default print to stderr. How much is possible when genuinely out of memory is another question though.

There’s currently no defined way for the allocation functions to recover from an error such as out of memory, they must terminate program execution. A longjmp or throwing a C++ exception will have undefined results. This may change in the future."

comment:3 Changed 3 months ago by Samuel Lelièvre

Cc: Samuel Lelièvre Paul Zimmermann added
Keywords: crash gmp added

comment:4 Changed 3 months ago by Dima Pasechnik

by the way, it's even easier to reproduce with gmpy2:

$ ./sage --python
Python 3.9.2 (default, Feb 28 2021, 17:03:44) 
[GCC 10.2.1 20210110] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import gmpy2
>>> from gmpy2 import mpz
>>> e=mpz(2**63)
>>> 2**e
gmp: overflow in mpz type
Aborted (core dumped)

Although it's not a Sage bug, it's gmpy2 bug - see https://github.com/aleaxit/gmpy/issues/280

Last edited 3 months ago by Dima Pasechnik (previous) (diff)
Note: See TracTickets for help on using tickets.