Skip to content

Commit ed0fde6

Browse files
committed
Fix changing of avma in call_python_func()
1 parent 4721314 commit ed0fde6

File tree

2 files changed

+35
-8
lines changed

2 files changed

+35
-8
lines changed

cypari2/closure.pyx

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ from cpython.object cimport PyObject_Call
4040
from cpython.ref cimport Py_INCREF
4141

4242
from .paridecl cimport *
43-
from .stack cimport new_gen, clone_gen_noclear, DetachGen
43+
from .stack cimport new_gen, new_gen_noclear, clone_gen_noclear, DetachGen
4444
from .gen cimport objtogen
4545

4646
try:
@@ -57,9 +57,12 @@ cdef inline GEN call_python_func_impl "call_python_func"(GEN* args, object py_fu
5757
The arguments are converted from ``GEN`` to a cypari ``gen`` before
5858
calling ``py_func``. The result is converted back to a PARI ``GEN``.
5959
"""
60+
# We need to ensure that nothing above avma is touched
61+
avmaguard = new_gen_noclear(<GEN>avma)
62+
6063
# How many arguments are there?
6164
cdef Py_ssize_t n = 0
62-
while args[n] != NULL:
65+
while args[n] is not NULL:
6366
n += 1
6467

6568
# Construct a Python tuple for args
@@ -78,9 +81,16 @@ cdef inline GEN call_python_func_impl "call_python_func"(GEN* args, object py_fu
7881
if r is None:
7982
return gnil
8083

84+
# Safely delete r and avmaguard
8185
d = DetachGen(objtogen(r))
8286
del r
83-
return d.detach()
87+
res = d.detach()
88+
d = DetachGen(avmaguard)
89+
del avmaguard
90+
d.detach()
91+
92+
return res
93+
8494

8595
# We rename this function to be able to call it with a different
8696
# signature. In particular, we want manual exception handling and we
@@ -166,6 +176,21 @@ cpdef Gen objtoclosure(f):
166176
>>> objtoclosure(printme)('matid(2)')
167177
[1, 0; 0, 1]
168178
179+
Construct the Riemann zeta function using a closure:
180+
181+
>>> from cypari2 import Pari; pari = Pari()
182+
>>> def coeffs(n):
183+
... return [1 for i in range(n)]
184+
>>> Z = pari.lfuncreate([coeffs, 0, [0], 1, 1, 1, 1])
185+
>>> Z.lfun(2)
186+
1.64493406684823
187+
188+
A trivial closure:
189+
190+
>>> f = pari(lambda x: x)
191+
>>> f(10)
192+
10
193+
169194
Test various kinds of errors:
170195
171196
>>> mul(4)

cypari2/stack.pyx

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -258,13 +258,15 @@ cdef class DetachGen:
258258
# Whatever happens, delete self.source
259259
self.source = None
260260

261-
# Verify that we hold the only reference to src
262-
if (<PyObject*>src).ob_refcnt != 1:
263-
raise SystemError("cannot detach a Gen which is still referenced")
264-
265261
# Delete src safely, keeping it available as GEN
266262
cdef GEN res = src.g
267-
if not (is_on_stack(res) or is_universal_constant(res)):
263+
if is_on_stack(res):
264+
# Verify that we hold the only reference to src
265+
if (<PyObject*>src).ob_refcnt != 1:
266+
raise SystemError("cannot detach a Gen which is still referenced")
267+
elif is_universal_constant(res):
268+
pass
269+
else:
268270
# Make a copy to the PARI stack
269271
res = gcopy(res)
270272

0 commit comments

Comments
 (0)