[pypy-svn] r72748 - in pypy/branch/cpython-extension/pypy/module/cpyext: . include test
afa at codespeak.net
afa at codespeak.net
Wed Mar 24 20:11:05 CET 2010
Author: afa
Date: Wed Mar 24 20:11:03 2010
New Revision: 72748
Modified:
pypy/branch/cpython-extension/pypy/module/cpyext/api.py
pypy/branch/cpython-extension/pypy/module/cpyext/boolobject.py
pypy/branch/cpython-extension/pypy/module/cpyext/dictobject.py
pypy/branch/cpython-extension/pypy/module/cpyext/include/pyerrors.h
pypy/branch/cpython-extension/pypy/module/cpyext/methodobject.py
pypy/branch/cpython-extension/pypy/module/cpyext/modsupport.py
pypy/branch/cpython-extension/pypy/module/cpyext/object.py
pypy/branch/cpython-extension/pypy/module/cpyext/pyerrors.py
pypy/branch/cpython-extension/pypy/module/cpyext/pythonrun.py
pypy/branch/cpython-extension/pypy/module/cpyext/stringobject.py
pypy/branch/cpython-extension/pypy/module/cpyext/test/test_cpyext.py
pypy/branch/cpython-extension/pypy/module/cpyext/tupleobject.py
pypy/branch/cpython-extension/pypy/module/cpyext/typeobject.py
Log:
Change exception handling in cpyext:
- ensure that every C function properly declares its error value
- check consistency between the return value and the exception stored in the threadstate
- remove from_ref_ex(), not needed any more.
Modified: pypy/branch/cpython-extension/pypy/module/cpyext/api.py
==============================================================================
--- pypy/branch/cpython-extension/pypy/module/cpyext/api.py (original)
+++ pypy/branch/cpython-extension/pypy/module/cpyext/api.py Wed Mar 24 20:11:03 2010
@@ -44,6 +44,7 @@
globals().update(rffi_platform.configure(CConfig_constants))
_NOT_SPECIFIED = object()
+CANNOT_FAIL = object()
class ApiFunction:
def __init__(self, argtypes, restype, callable, borrowed, error):
@@ -64,12 +65,18 @@
assert len(self.argnames) == len(self.argtypes)
def cpython_api(argtypes, restype, borrowed=False, error=_NOT_SPECIFIED):
- if restype is PyObject and error is _NOT_SPECIFIED:
- error = None
+ if error is _NOT_SPECIFIED:
+ if restype is PyObject:
+ error = lltype.nullptr(PyObject.TO)
+ elif restype is lltype.Void:
+ error = CANNOT_FAIL
def decorate(func):
api_function = ApiFunction(argtypes, restype, func, borrowed, error)
+ if error is _NOT_SPECIFIED:
+ raise ValueError("function %s has no return value for exceptions"
+ % func)
def unwrapper(space, *args):
"NOT_RPYTHON: XXX unsure"
newargs = []
@@ -171,7 +178,6 @@
def make_ref(space, w_obj, borrowed=False):
if w_obj is None:
return lltype.nullptr(PyObject.TO)
- #raise NullPointerException("Trying to pass a NULL reference")
assert isinstance(w_obj, W_Root)
state = space.fromcache(State)
py_obj = state.py_objects_w2r.get(w_obj)
@@ -209,9 +215,9 @@
return py_obj
def from_ref(space, ref):
- state = space.fromcache(State)
if not ref:
- raise NullPointerException("Null pointer dereference!")
+ return None
+ state = space.fromcache(State)
ptr = ctypes.addressof(ref._obj._storage)
try:
obj = state.py_objects_r2w[ptr]
@@ -251,24 +257,25 @@
retval = callable(space, *boxed_args)
print >>sys.stderr, " DONE"
except OperationError, e:
+ failed = True
e.normalize_exception(space)
state.exc_type = e.w_type
state.exc_value = e.get_w_value(space)
except BaseException, e:
+ failed = True
state.exc_type = space.w_SystemError
state.exc_value = space.wrap(str(e))
import traceback
traceback.print_exc()
+ else:
+ failed = False
- if state.exc_value is not None:
- restype = callable.api_func.restype
- if restype is lltype.Void:
- return
- if restype is PyObject:
- return lltype.nullptr(PyObject.TO)
- if restype in (Py_ssize_t, rffi.INT_real):
- return rffi.cast(restype, -1)
- assert False, "Unknown return type"
+ if failed:
+ error_value = callable.api_func.error_value
+ if error_value is CANNOT_FAIL:
+ raise SystemError("The function %r was not supposed to fail"
+ % (callable,))
+ return error_value
if callable.api_func.restype is PyObject:
retval = make_ref(space, retval, borrowed=callable.api_func.borrowed)
@@ -413,6 +420,8 @@
def generic_cpy_call(space, func, *args, **kwargs):
from pypy.module.cpyext.macros import Py_DECREF
+ from pypy.module.cpyext.pyerrors import PyErr_Occurred
+
decref_args = kwargs.pop("decref_args", True)
assert not kwargs
boxed_args = []
@@ -424,9 +433,24 @@
result = func(*boxed_args)
try:
FT = lltype.typeOf(func).TO
- if FT.RESULT is not lltype.Void:
- ret = from_ref_ex(space, result)
- Py_DECREF(space, ret)
+ if FT.RESULT is PyObject:
+ ret = from_ref(space, result)
+
+ # Check for exception consistency
+ has_error = PyErr_Occurred(space) is not None
+ has_result = ret is not None
+ if has_error and has_result:
+ raise OperationError(space.w_SystemError, space.wrap(
+ "An exception was set, but function returned a value"))
+ elif not has_error and not has_result:
+ raise OperationError(space.w_SystemError, space.wrap(
+ "Function returned a NULL result without setting an exception"))
+
+ if has_error:
+ state = space.fromcache(State)
+ state.check_and_raise_exception()
+
+ Py_DECREF(space, ret) # XXX WHY??
return ret
finally:
if decref_args:
@@ -434,19 +458,3 @@
if arg is not None and isinstance(arg, W_Root):
Py_DECREF(space, arg)
-def from_ref_ex(space, result):
- try:
- ret = from_ref(space, result)
- except NullPointerException:
- state = space.fromcache(State)
- state.check_and_raise_exception()
- assert False, "NULL returned but no exception set"
- except InvalidPointerException:
- if not we_are_translated():
- import sys
- print >>sys.stderr, "Calling a C function return an invalid PyObject" \
- " pointer."
- raise
- return ret
-
-
Modified: pypy/branch/cpython-extension/pypy/module/cpyext/boolobject.py
==============================================================================
--- pypy/branch/cpython-extension/pypy/module/cpyext/boolobject.py (original)
+++ pypy/branch/cpython-extension/pypy/module/cpyext/boolobject.py Wed Mar 24 20:11:03 2010
@@ -1,7 +1,8 @@
from pypy.rpython.lltypesystem import rffi, lltype
-from pypy.module.cpyext.api import cpython_api, PyObject, general_check
+from pypy.module.cpyext.api import cpython_api, PyObject, CANNOT_FAIL
+from pypy.module.cpyext.api import general_check
- at cpython_api([PyObject], rffi.INT_real)
+ at cpython_api([PyObject], rffi.INT_real, error=CANNOT_FAIL)
def PyBool_Check(space, w_obj):
w_type = space.w_bool
return general_check(space, w_obj, w_type)
Modified: pypy/branch/cpython-extension/pypy/module/cpyext/dictobject.py
==============================================================================
--- pypy/branch/cpython-extension/pypy/module/cpyext/dictobject.py (original)
+++ pypy/branch/cpython-extension/pypy/module/cpyext/dictobject.py Wed Mar 24 20:11:03 2010
@@ -1,19 +1,19 @@
from pypy.rpython.lltypesystem import rffi, lltype
-from pypy.module.cpyext.api import cpython_api, PyObject
+from pypy.module.cpyext.api import cpython_api, PyObject, CANNOT_FAIL
from pypy.module.cpyext.pyerrors import PyErr_BadInternalCall
@cpython_api([], PyObject)
def PyDict_New(space):
return space.newdict()
- at cpython_api([PyObject], rffi.INT_real)
+ at cpython_api([PyObject], rffi.INT_real, error=CANNOT_FAIL)
def PyDict_Check(space, w_obj):
w_type = space.w_dict
w_obj_type = space.type(w_obj)
return space.is_w(w_obj_type, w_type) or space.is_true(space.issubtype(w_obj_type, w_type))
- at cpython_api([PyObject, rffi.CCHARP, PyObject], rffi.INT_real)
+ at cpython_api([PyObject, rffi.CCHARP, PyObject], rffi.INT_real, error=-1)
def PyDict_SetItemString(space, w_dict, key_ptr, w_obj):
if PyDict_Check(space, w_dict):
key = rffi.charp2str(key_ptr)
Modified: pypy/branch/cpython-extension/pypy/module/cpyext/include/pyerrors.h
==============================================================================
--- pypy/branch/cpython-extension/pypy/module/cpyext/include/pyerrors.h (original)
+++ pypy/branch/cpython-extension/pypy/module/cpyext/include/pyerrors.h Wed Mar 24 20:11:03 2010
@@ -10,7 +10,7 @@
PyAPI_DATA(PyObject *) PyExc_Exception;
void PyErr_SetString(PyObject *, char *);
PyObject * PyErr_Occurred(void);
-void PyErr_Clear(PyObject *, char *);
+void PyErr_Clear();
#ifdef __cplusplus
}
Modified: pypy/branch/cpython-extension/pypy/module/cpyext/methodobject.py
==============================================================================
--- pypy/branch/cpython-extension/pypy/module/cpyext/methodobject.py (original)
+++ pypy/branch/cpython-extension/pypy/module/cpyext/methodobject.py Wed Mar 24 20:11:03 2010
@@ -4,11 +4,13 @@
from pypy.interpreter.argument import Arguments
from pypy.interpreter.typedef import interp_attrproperty, interp_attrproperty_w
from pypy.interpreter.gateway import interp2app, unwrap_spec
+from pypy.interpreter.error import OperationError
from pypy.interpreter.function import BuiltinFunction, Method
from pypy.rpython.lltypesystem import rffi, lltype
from pypy.module.cpyext.api import PyObject, from_ref, \
- make_ref, generic_cpy_call, from_ref_ex
+ make_ref, generic_cpy_call
from pypy.module.cpyext.state import State
+from pypy.module.cpyext.pyerrors import PyErr_Occurred
from pypy.rlib.objectmodel import we_are_translated
Modified: pypy/branch/cpython-extension/pypy/module/cpyext/modsupport.py
==============================================================================
--- pypy/branch/cpython-extension/pypy/module/cpyext/modsupport.py (original)
+++ pypy/branch/cpython-extension/pypy/module/cpyext/modsupport.py Wed Mar 24 20:11:03 2010
@@ -1,6 +1,6 @@
from pypy.rpython.lltypesystem import rffi, lltype
from pypy.module.cpyext.api import cpython_api, cpython_struct, PyObject, \
- METH_STATIC, METH_CLASS, METH_COEXIST, general_check
+ METH_STATIC, METH_CLASS, METH_COEXIST, general_check, CANNOT_FAIL
from pypy.interpreter.module import Module
from pypy.module.cpyext.methodobject import PyCFunction_NewEx, PyDescr_NewMethod
from pypy.module.cpyext.pyerrors import PyErr_BadInternalCall
@@ -69,7 +69,7 @@
dict_w[methodname] = w_obj
- at cpython_api([PyObject], rffi.INT_real)
+ at cpython_api([PyObject], rffi.INT_real, error=CANNOT_FAIL)
def PyModule_Check(space, w_obj):
w_type = space.gettypeobject(Module.typedef)
return general_check(space, w_obj, w_type)
Modified: pypy/branch/cpython-extension/pypy/module/cpyext/object.py
==============================================================================
--- pypy/branch/cpython-extension/pypy/module/cpyext/object.py (original)
+++ pypy/branch/cpython-extension/pypy/module/cpyext/object.py Wed Mar 24 20:11:03 2010
@@ -1,6 +1,6 @@
from pypy.rpython.lltypesystem import rffi, lltype
from pypy.module.cpyext.api import cpython_api, PyObject, make_ref, from_ref, \
- generic_cpy_call
+ generic_cpy_call, CANNOT_FAIL
from pypy.module.cpyext.state import State
from pypy.module.cpyext.macros import Py_INCREF, Py_DECREF
from pypy.module.cpyext.typeobject import PyTypeObjectPtr, W_PyCTypeObject, W_PyCObject
@@ -34,12 +34,12 @@
def PyObject_Not(space, w_obj):
return not space.is_true(w_obj)
- at cpython_api([PyObject, PyObject], rffi.INT_real)
+ at cpython_api([PyObject, PyObject], rffi.INT_real, error=CANNOT_FAIL)
def PyObject_HasAttr(space, w_obj, w_name):
w_res = operation.hasattr(space, w_obj, w_name)
return space.is_true(w_res)
- at cpython_api([PyObject, PyObject, PyObject], rffi.INT_real)
+ at cpython_api([PyObject, PyObject, PyObject], rffi.INT_real, error=-1)
def PyObject_SetAttr(space, w_obj, w_name, w_value):
operation.setattr(space, w_obj, w_name, w_value)
return 0
Modified: pypy/branch/cpython-extension/pypy/module/cpyext/pyerrors.py
==============================================================================
--- pypy/branch/cpython-extension/pypy/module/cpyext/pyerrors.py (original)
+++ pypy/branch/cpython-extension/pypy/module/cpyext/pyerrors.py Wed Mar 24 20:11:03 2010
@@ -6,8 +6,9 @@
@cpython_api([PyObject, rffi.CCHARP], lltype.Void)
def PyErr_SetString(space, w_type, message_ptr):
message = rffi.charp2str(message_ptr)
- w_obj = space.call_function(w_type, space.wrap(message))
- raise OperationError(w_type, w_obj)
+ state = space.fromcache(State)
+ state.exc_type = w_type
+ state.exc_value = space.call_function(w_type, space.wrap(message))
@cpython_api([], PyObject)
def PyErr_Occurred(space):
Modified: pypy/branch/cpython-extension/pypy/module/cpyext/pythonrun.py
==============================================================================
--- pypy/branch/cpython-extension/pypy/module/cpyext/pythonrun.py (original)
+++ pypy/branch/cpython-extension/pypy/module/cpyext/pythonrun.py Wed Mar 24 20:11:03 2010
@@ -1,6 +1,6 @@
from pypy.rpython.lltypesystem import rffi, lltype
-from pypy.module.cpyext.api import cpython_api
+from pypy.module.cpyext.api import cpython_api, CANNOT_FAIL
- at cpython_api([], rffi.INT_real)
+ at cpython_api([], rffi.INT_real, error=CANNOT_FAIL)
def Py_IsInitialized(space):
return 1
Modified: pypy/branch/cpython-extension/pypy/module/cpyext/stringobject.py
==============================================================================
--- pypy/branch/cpython-extension/pypy/module/cpyext/stringobject.py (original)
+++ pypy/branch/cpython-extension/pypy/module/cpyext/stringobject.py Wed Mar 24 20:11:03 2010
@@ -11,6 +11,6 @@
s = rffi.charp2str(char_p)
return space.wrap(s)
- at cpython_api([PyObject], Py_ssize_t)
+ at cpython_api([PyObject], Py_ssize_t, error=-1)
def PyString_Size(space, w_obj):
return space.int_w(space.len(w_obj))
Modified: pypy/branch/cpython-extension/pypy/module/cpyext/test/test_cpyext.py
==============================================================================
--- pypy/branch/cpython-extension/pypy/module/cpyext/test/test_cpyext.py (original)
+++ pypy/branch/cpython-extension/pypy/module/cpyext/test/test_cpyext.py Wed Mar 24 20:11:03 2010
@@ -17,7 +17,7 @@
def PyPy_Crash1(space):
1/0
- at api.cpython_api([], lltype.Signed)
+ at api.cpython_api([], lltype.Signed, error=-1)
def PyPy_Crash2(space):
1/0
@@ -366,7 +366,6 @@
def test_internal_exceptions(self):
- skip("Useful to see how programming errors look like")
import sys
init = """
if (Py_IsInitialized())
@@ -384,14 +383,41 @@
return NULL;
return PyFloat_FromDouble(a);
}
+ static PyObject* foo_crash3(PyObject* self, PyObject *args)
+ {
+ int a = PyPy_Crash2();
+ if (a == -1)
+ PyErr_Clear();
+ return PyFloat_FromDouble(a);
+ }
+ static PyObject* foo_crash4(PyObject* self, PyObject *args)
+ {
+ int a = PyPy_Crash2();
+ return PyFloat_FromDouble(a);
+ }
+ static PyObject* foo_clear(PyObject* self, PyObject *args)
+ {
+ PyErr_Clear();
+ return NULL;
+ }
static PyMethodDef methods[] = {
{ "crash1", foo_crash1, METH_NOARGS },
{ "crash2", foo_crash2, METH_NOARGS },
+ { "crash3", foo_crash3, METH_NOARGS },
+ { "crash4", foo_crash4, METH_NOARGS },
+ { "clear", foo_clear, METH_NOARGS },
{ NULL }
};
"""
module = self.import_module(name='foo', init=init, body=body)
- module.crash1()
- module.crash2()
+ # uncaught interplevel exceptions are turned into SystemError
+ raises(SystemError, module.crash1)
+ raises(SystemError, module.crash2)
+ # caught exception
+ assert module.crash3() == -1
+ # An exception was set, but function returned a value
+ raises(SystemError, module.crash4)
+ # No exception set, but NULL returned
+ raises(SystemError, module.clear)
Modified: pypy/branch/cpython-extension/pypy/module/cpyext/tupleobject.py
==============================================================================
--- pypy/branch/cpython-extension/pypy/module/cpyext/tupleobject.py (original)
+++ pypy/branch/cpython-extension/pypy/module/cpyext/tupleobject.py Wed Mar 24 20:11:03 2010
@@ -8,7 +8,7 @@
def PyTuple_New(space, size):
return space.newtuple([space.w_None] * size)
- at cpython_api([PyObject, Py_ssize_t, PyObject], rffi.INT_real)
+ at cpython_api([PyObject, Py_ssize_t, PyObject], rffi.INT_real, error=-1)
def PyTuple_SetItem(space, w_t, pos, w_obj):
assert isinstance(w_t, W_TupleObject)
w_t.wrappeditems[pos] = w_obj
Modified: pypy/branch/cpython-extension/pypy/module/cpyext/typeobject.py
==============================================================================
--- pypy/branch/cpython-extension/pypy/module/cpyext/typeobject.py (original)
+++ pypy/branch/cpython-extension/pypy/module/cpyext/typeobject.py Wed Mar 24 20:11:03 2010
@@ -16,7 +16,7 @@
from pypy.interpreter.module import Module
from pypy.module.cpyext.modsupport import PyMethodDef, convert_method_defs
from pypy.module.cpyext.state import State
-from pypy.module.cpyext.methodobject import from_ref_ex, generic_cpy_call
+from pypy.module.cpyext.methodobject import generic_cpy_call
PyTypeObject = lltype.ForwardReference()
@@ -238,7 +238,7 @@
def PyType_Ready(space, pto):
"Implemented in typeobject.c"
- at cpython_api([PyTypeObjectPtr], rffi.INT_real)
+ at cpython_api([PyTypeObjectPtr], rffi.INT_real, error=-1)
def PyPyType_Register(space, pto):
state = space.fromcache(State)
ptr = ctypes.addressof(pto._obj._storage)
More information about the Pypy-commit
mailing list