-
-
Notifications
You must be signed in to change notification settings - Fork 674
Fix Ctrl-C segfaults in sage.libs.gap #40613
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 10 commits
e0b0c06
4d1f19f
c6b76b6
f9c186d
a9473ca
fc16eae
a887924
a219ac9
0b66eba
e1e8d62
2ca060f
7c48f94
fb458ad
51c81b0
bab97f6
b298ca8
867cf66
cd93bdf
794b427
ee6af07
e7bb222
d9bd3c2
e79bdd7
3220d8f
24065b5
041fcdf
50157d7
b550b36
677c2f1
1af02c2
f39be09
36da2ca
3a6d006
8b8c496
6e74192
47826c2
c1adeb9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -16,12 +16,11 @@ | |
# **************************************************************************** | ||
|
||
from cpython.object cimport Py_EQ, Py_NE, Py_LE, Py_GE, Py_LT, Py_GT | ||
from cysignals.signals cimport sig_on, sig_off | ||
|
||
from sage.libs.gap.gap_includes cimport * | ||
from sage.libs.gap.libgap import libgap | ||
from sage.libs.gap.util cimport * | ||
from sage.libs.gap.util import GAPError | ||
from sage.libs.gap.util import GAPError, gap_sig_on, gap_sig_off | ||
from sage.libs.gmp.mpz cimport * | ||
from sage.libs.gmp.pylong cimport mpz_get_pylong | ||
from sage.cpython.string cimport str_to_bytes, char_to_str | ||
|
@@ -935,13 +934,21 @@ | |
if self._compare_by_id: | ||
return id(self) == id(other) | ||
cdef GapElement c_other = <GapElement>other | ||
sig_on() | ||
|
||
try: | ||
gap_sig_on() | ||
GAP_Enter() | ||
return GAP_EQ(self.value, c_other.value) | ||
except GAPError as e: | ||
if "user interrupt" in str(e): | ||
# Ctrl-C | ||
raise KeyboardInterrupt from e | ||
else: | ||
raise | ||
finally: | ||
GAP_Leave() | ||
sig_off() | ||
gap_sig_off() | ||
|
||
|
||
cdef bint _compare_less(self, Element other) except -2: | ||
""" | ||
|
@@ -957,13 +964,21 @@ | |
if self._compare_by_id: | ||
return id(self) < id(other) | ||
cdef GapElement c_other = <GapElement>other | ||
sig_on() | ||
|
||
try: | ||
gap_sig_on() | ||
GAP_Enter() | ||
return GAP_LT(self.value, c_other.value) | ||
except GAPError as e: | ||
if "user interrupt" in str(e): | ||
# Ctrl-C | ||
raise KeyboardInterrupt from e | ||
else: | ||
raise | ||
finally: | ||
GAP_Leave() | ||
sig_off() | ||
gap_sig_off() | ||
|
||
|
||
cpdef _add_(self, right): | ||
r""" | ||
|
@@ -986,12 +1001,18 @@ | |
""" | ||
cdef Obj result | ||
try: | ||
sig_GAP_Enter() | ||
sig_on() | ||
gap_sig_on() | ||
GAP_Enter() | ||
result = GAP_SUM(self.value, (<GapElement>right).value) | ||
sig_off() | ||
except GAPError as e: | ||
if "user interrupt" in str(e): | ||
# Ctrl-C | ||
raise KeyboardInterrupt from e | ||
else: | ||
raise | ||
finally: | ||
GAP_Leave() | ||
gap_sig_off() | ||
return make_any_gap_element(self.parent(), result) | ||
|
||
cpdef _sub_(self, right): | ||
|
@@ -1014,12 +1035,18 @@ | |
""" | ||
cdef Obj result | ||
try: | ||
sig_GAP_Enter() | ||
sig_on() | ||
gap_sig_on() | ||
GAP_Enter() | ||
result = GAP_DIFF(self.value, (<GapElement>right).value) | ||
sig_off() | ||
except GAPError as e: | ||
if "user interrupt" in str(e): | ||
# Ctrl-C | ||
raise KeyboardInterrupt from e | ||
else: | ||
raise | ||
finally: | ||
GAP_Leave() | ||
gap_sig_off() | ||
return make_any_gap_element(self.parent(), result) | ||
|
||
cpdef _mul_(self, right): | ||
|
@@ -1043,12 +1070,18 @@ | |
""" | ||
cdef Obj result | ||
try: | ||
sig_GAP_Enter() | ||
sig_on() | ||
gap_sig_on() | ||
GAP_Enter() | ||
result = GAP_PROD(self.value, (<GapElement>right).value) | ||
sig_off() | ||
except GAPError as e: | ||
if "user interrupt" in str(e): | ||
# Ctrl-C | ||
raise KeyboardInterrupt from e | ||
else: | ||
raise | ||
finally: | ||
GAP_Leave() | ||
gap_sig_off() | ||
return make_any_gap_element(self.parent(), result) | ||
|
||
cpdef _div_(self, right): | ||
|
@@ -1077,12 +1110,18 @@ | |
""" | ||
cdef Obj result | ||
try: | ||
sig_GAP_Enter() | ||
sig_on() | ||
gap_sig_on() | ||
GAP_Enter() | ||
result = GAP_QUO(self.value, (<GapElement>right).value) | ||
sig_off() | ||
except GAPError as e: | ||
if "user interrupt" in str(e): | ||
# Ctrl-C | ||
raise KeyboardInterrupt from e | ||
else: | ||
raise | ||
finally: | ||
GAP_Leave() | ||
gap_sig_off() | ||
return make_any_gap_element(self.parent(), result) | ||
|
||
cpdef _mod_(self, right): | ||
|
@@ -1104,12 +1143,18 @@ | |
""" | ||
cdef Obj result | ||
try: | ||
sig_GAP_Enter() | ||
sig_on() | ||
gap_sig_on() | ||
GAP_Enter() | ||
result = GAP_MOD(self.value, (<GapElement>right).value) | ||
sig_off() | ||
except GAPError as e: | ||
if "user interrupt" in str(e): | ||
# Ctrl-C | ||
raise KeyboardInterrupt from e | ||
else: | ||
raise | ||
|
||
finally: | ||
GAP_Leave() | ||
gap_sig_off() | ||
return make_any_gap_element(self.parent(), result) | ||
|
||
cpdef _pow_(self, other): | ||
|
@@ -1136,7 +1181,7 @@ | |
|
||
sage: a, b = libgap.GL(1000, 3).GeneratorsOfGroup(); g = a * b | ||
sage: from sage.doctest.util import ensure_interruptible_after | ||
sage: with ensure_interruptible_after(0.5): g ^ (2 ^ 10000) | ||
Check failure on line 1184 in src/sage/libs/gap/element.pyx
|
||
|
||
sage: libgap.CyclicGroup(2) ^ 2 | ||
Traceback (most recent call last): | ||
|
@@ -1151,12 +1196,18 @@ | |
method found for `InverseMutable' on 1 arguments | ||
""" | ||
try: | ||
sig_GAP_Enter() | ||
sig_on() | ||
gap_sig_on() | ||
GAP_Enter() # GAPError raised from here | ||
result = GAP_POW(self.value, (<GapElement>other).value) | ||
sig_off() | ||
except GAPError as e: | ||
if "user interrupt" in str(e): | ||
# Ctrl-C | ||
raise KeyboardInterrupt from e | ||
else: | ||
raise | ||
finally: | ||
GAP_Leave() | ||
gap_sig_off() | ||
return make_any_gap_element(self._parent, result) | ||
|
||
cpdef _pow_int(self, other): | ||
|
@@ -2498,36 +2549,40 @@ | |
cdef Obj result = NULL | ||
cdef Obj arg_list | ||
cdef int n = len(args) | ||
cdef volatile Obj v2 | ||
|
||
if n > 0 and n <= 3: | ||
libgap = self.parent() | ||
a = [x if isinstance(x, GapElement) else libgap(x) for x in args] | ||
cdef Obj a[3] | ||
|
||
if n <= 3: | ||
if not all(isinstance(x, GapElement) for x in args): | ||
libgap = self.parent() | ||
args = tuple(x if isinstance(x, GapElement) else libgap(x) for x in args) | ||
for i in range(n): | ||
x = args[i] | ||
a[i] = (<GapElement>x).value | ||
else: | ||
arg_list = make_gap_list(args) | ||
|
||
try: | ||
sig_GAP_Enter() | ||
sig_on() | ||
gap_sig_on() | ||
GAP_Enter() | ||
if n == 0: | ||
result = GAP_CallFunc0Args(self.value) | ||
elif n == 1: | ||
result = GAP_CallFunc1Args(self.value, | ||
(<GapElement>a[0]).value) | ||
result = GAP_CallFunc1Args(self.value, a[0]) | ||
elif n == 2: | ||
result = GAP_CallFunc2Args(self.value, | ||
(<GapElement>a[0]).value, | ||
(<GapElement>a[1]).value) | ||
result = GAP_CallFunc2Args(self.value, a[0], a[1]) | ||
elif n == 3: | ||
v2 = (<GapElement>a[2]).value | ||
result = GAP_CallFunc3Args(self.value, | ||
(<GapElement>a[0]).value, | ||
(<GapElement>a[1]).value, | ||
v2) | ||
result = GAP_CallFunc3Args(self.value, a[0], a[1], a[2]) | ||
else: | ||
arg_list = make_gap_list(args) | ||
result = GAP_CallFuncList(self.value, arg_list) | ||
sig_off() | ||
except GAPError as e: | ||
if "user interrupt" in str(e): | ||
# Ctrl-C | ||
raise KeyboardInterrupt from e | ||
else: | ||
raise | ||
finally: | ||
GAP_Leave() | ||
gap_sig_off() | ||
if result == NULL: | ||
# We called a procedure that does not return anything | ||
return None | ||
|
@@ -3151,13 +3206,20 @@ | |
""" | ||
cdef UInt i = self.record_name_to_index(name) | ||
cdef Obj result | ||
sig_on() | ||
|
||
try: | ||
gap_sig_on() | ||
GAP_Enter() | ||
result = ELM_REC(self.value, i) | ||
except GAPError as e: | ||
if "user interrupt" in str(e): | ||
# Ctrl-C | ||
raise KeyboardInterrupt from e | ||
else: | ||
raise | ||
finally: | ||
GAP_Leave() | ||
sig_off() | ||
gap_sig_off() | ||
return make_any_gap_element(self.parent(), result) | ||
|
||
def sage(self): | ||
|
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if the logic below (raise AlarmInterrupt instead of KeyboardInterrupt) are correctly implemented, this change wouldn't be necessary.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've further simplified this down to a one-line change, using the fact that
AlarmInterrupt
is a subclass ofKeyboardInterrupt
. Instead of catchingAlarmInterrupt
, we can catchKeyboardInterrupt
, and then check,AlarmInterrupt
?I prefer this to hacking
AlarmInterrupt
into the GAP code at this point becausesage.libs.gap
is otherwise free of cysignals. To raise theAlarmInterrupt
fromsage.libs.gap
we'd have to,meson.build
AlarmInterrupt
last_signal
variablelast_signal
whenever a handler is calledlast_signal
when raising aGAPError
and convert it to the right thingSince this is all for the benefit of one doctest method, it just seems easier to add the one line in that doctest method?