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: |
Description
gmp sometimes calls abort()
. (For example,this StackOverflow post says "whenever you try to create or calculate a number with more than 2^{31} - 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:2 Changed 3 months ago by
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
Cc: | Samuel Lelièvre Paul Zimmermann added |
---|---|
Keywords: | crash gmp added |
comment:4 Changed 3 months ago by
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
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.