Author: Armin Rigo <[email protected]>
Branch: hpy
Changeset: r98117:1b05295469eb
Date: 2019-11-18 18:38 +0100
http://bitbucket.org/pypy/pypy/changeset/1b05295469eb/

Log:    (antocuni, arigo)

        Allow llhelper functions to propagate exceptions from RPython to
        RPython via C. This already works after translation, but we need to
        convince ll2ctypes.

diff --git a/rpython/rtyper/lltypesystem/ll2ctypes.py 
b/rpython/rtyper/lltypesystem/ll2ctypes.py
--- a/rpython/rtyper/lltypesystem/ll2ctypes.py
+++ b/rpython/rtyper/lltypesystem/ll2ctypes.py
@@ -869,6 +869,9 @@
                             llinterp = LLInterpreter.current_interpreter
                             llinterp._store_exception(lle)
                             return 0
+                    return ctypes_return_value(llres)
+
+                def ctypes_return_value(llres):
                     assert lltype.typeOf(llres) == T.TO.RESULT
                     if T.TO.RESULT is lltype.Void:
                         return None
@@ -891,7 +894,12 @@
                         #    import pdb; pdb.post_mortem(sys.exc_traceback)
                         global _callback_exc_info
                         _callback_exc_info = sys.exc_info()
-                        raise
+                        if hasattr(getattr(container, '_callable', None),
+                                   '_llhelper_can_raise_'):
+                            llres = T.TO.RESULT._defl()
+                            return ctypes_return_value(llres)
+                        else:
+                            raise
 
                 if isinstance(T.TO.RESULT, lltype.Ptr):
                     TMod = lltype.Ptr(lltype.FuncType(T.TO.ARGS,
@@ -974,7 +982,7 @@
 
         return llobj
 
-def ctypes2lltype(T, cobj):
+def ctypes2lltype(T, cobj, force_real_ctypes_function=False):
     """Convert the ctypes object 'cobj' to its lltype equivalent.
     'T' is the expected lltype type.
     """
@@ -1045,7 +1053,7 @@
                 # or goes out of scope, then we crash.  CTypes is fun.
                 # It works if we cast it now to an int and back.
                 cobjkey = intmask(ctypes.cast(cobj, ctypes.c_void_p).value)
-                if cobjkey in _int2obj:
+                if cobjkey in _int2obj and not force_real_ctypes_function:
                     container = _int2obj[cobjkey]
                 else:
                     name = getattr(cobj, '__name__', '?')
diff --git a/rpython/rtyper/lltypesystem/test/test_ll2ctypes.py 
b/rpython/rtyper/lltypesystem/test/test_ll2ctypes.py
--- a/rpython/rtyper/lltypesystem/test/test_ll2ctypes.py
+++ b/rpython/rtyper/lltypesystem/test/test_ll2ctypes.py
@@ -1,4 +1,4 @@
-import py
+import py, pytest
 import sys, struct
 import ctypes
 from rpython.rtyper.lltypesystem import lltype, rffi, llmemory
@@ -480,6 +480,28 @@
         assert res == 42
         assert not ALLOCATED     # detects memory leaks in the test
 
+    def test_funcptr_can_raise(self, monkeypatch):
+        class FooError(Exception):
+            pass
+        def dummy(n):
+            raise FooError(n + 2)
+        dummy._llhelper_can_raise_ = True
+
+        FUNCTYPE = lltype.FuncType([lltype.Signed], lltype.Signed)
+        cdummy = lltype2ctypes(llhelper(lltype.Ptr(FUNCTYPE), dummy))
+        # here we pretend there is C in the middle
+        lldummy = ctypes2lltype(lltype.Ptr(FUNCTYPE), cdummy,
+                                force_real_ctypes_function=True)
+        seen = []
+        def custom_except_hook(*args):
+            seen.append(args)
+        monkeypatch.setattr(sys, 'excepthook', custom_except_hook)
+        with pytest.raises(FooError) as exc:
+            lldummy(41)
+        assert exc.value.args == (41 + 2,)
+        assert not seen
+        assert not ALLOCATED     # detects memory leaks in the test
+
     def test_funcptr2(self):
         FUNCTYPE = lltype.FuncType([rffi.CCHARP], rffi.LONG)
         cstrlen = standard_c_lib.strlen
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to