[pypy-commit] pypy default: Merged in Dodan/pypy_ctypes/pypy_ctypes_nosegfault_nofastpath (pull request #547)
cfbolz
pypy.commits at gmail.com
Fri May 19 08:53:10 EDT 2017
Author: Carl Friedrich Bolz <cfbolz at gmx.de>
Branch:
Changeset: r91344:8b4ebb4d87c8
Date: 2017-05-19 12:52 +0000
http://bitbucket.org/pypy/pypy/changeset/8b4ebb4d87c8/
Log: Merged in Dodan/pypy_ctypes/pypy_ctypes_nosegfault_nofastpath (pull
request #547)
fixed ctypes segfault by removing fastpath.
Approved-by: Carl Friedrich Bolz <cfbolz at gmx.de> Approved-by:
Antonio Cuni <anto.cuni+2 at gmail.com>
diff --git a/lib_pypy/_ctypes/function.py b/lib_pypy/_ctypes/function.py
--- a/lib_pypy/_ctypes/function.py
+++ b/lib_pypy/_ctypes/function.py
@@ -1,4 +1,3 @@
-
from _ctypes.basics import _CData, _CDataMeta, cdata_from_address
from _ctypes.primitive import SimpleType, _SimpleCData
from _ctypes.basics import ArgumentError, keepalive_key
@@ -9,13 +8,16 @@
import sys
import traceback
-try: from __pypy__ import builtinify
-except ImportError: builtinify = lambda f: f
+
+try:
+ from __pypy__ import builtinify
+except ImportError:
+ builtinify = lambda f: f
# XXX this file needs huge refactoring I fear
-PARAMFLAG_FIN = 0x1
-PARAMFLAG_FOUT = 0x2
+PARAMFLAG_FIN = 0x1
+PARAMFLAG_FOUT = 0x2
PARAMFLAG_FLCID = 0x4
PARAMFLAG_COMBINED = PARAMFLAG_FIN | PARAMFLAG_FOUT | PARAMFLAG_FLCID
@@ -24,9 +26,9 @@
PARAMFLAG_FIN,
PARAMFLAG_FIN | PARAMFLAG_FOUT,
PARAMFLAG_FIN | PARAMFLAG_FLCID
- )
+)
-WIN64 = sys.platform == 'win32' and sys.maxint == 2**63 - 1
+WIN64 = sys.platform == 'win32' and sys.maxint == 2 ** 63 - 1
def get_com_error(errcode, riid, pIunk):
@@ -35,6 +37,7 @@
from _ctypes import COMError
return COMError(errcode, None, None)
+
@builtinify
def call_function(func, args):
"Only for debugging so far: So that we can call CFunction instances"
@@ -94,14 +97,9 @@
"item %d in _argtypes_ has no from_param method" % (
i + 1,))
self._argtypes_ = list(argtypes)
- self._check_argtypes_for_fastpath()
+
argtypes = property(_getargtypes, _setargtypes)
- def _check_argtypes_for_fastpath(self):
- if all([hasattr(argtype, '_ffiargshape_') for argtype in self._argtypes_]):
- fastpath_cls = make_fastpath_subclass(self.__class__)
- fastpath_cls.enable_fastpath_maybe(self)
-
def _getparamflags(self):
return self._paramflags
@@ -126,27 +124,26 @@
raise TypeError(
"paramflags must be a sequence of (int [,string [,value]]) "
"tuples"
- )
+ )
if not isinstance(flag, int):
raise TypeError(
"paramflags must be a sequence of (int [,string [,value]]) "
"tuples"
- )
+ )
_flag = flag & PARAMFLAG_COMBINED
if _flag == PARAMFLAG_FOUT:
typ = self._argtypes_[idx]
if getattr(typ, '_ffiargshape_', None) not in ('P', 'z', 'Z'):
raise TypeError(
"'out' parameter %d must be a pointer type, not %s"
- % (idx+1, type(typ).__name__)
- )
+ % (idx + 1, type(typ).__name__)
+ )
elif _flag not in VALID_PARAMFLAGS:
raise TypeError("paramflag value %d not supported" % flag)
self._paramflags = paramflags
paramflags = property(_getparamflags, _setparamflags)
-
def _getrestype(self):
return self._restype_
@@ -156,7 +153,7 @@
from ctypes import c_int
restype = c_int
if not (isinstance(restype, _CDataMeta) or restype is None or
- callable(restype)):
+ callable(restype)):
raise TypeError("restype must be a type, a callable, or None")
self._restype_ = restype
@@ -168,15 +165,18 @@
def _geterrcheck(self):
return getattr(self, '_errcheck_', None)
+
def _seterrcheck(self, errcheck):
if not callable(errcheck):
raise TypeError("The errcheck attribute must be callable")
self._errcheck_ = errcheck
+
def _delerrcheck(self):
try:
del self._errcheck_
except AttributeError:
pass
+
errcheck = property(_geterrcheck, _seterrcheck, _delerrcheck)
def _ffishapes(self, args, restype):
@@ -188,7 +188,7 @@
raise TypeError("invalid result type for callback function")
restype = restype._ffiargshape_
else:
- restype = 'O' # void
+ restype = 'O' # void
return argtypes, restype
def _set_address(self, address):
@@ -201,7 +201,7 @@
def __init__(self, *args):
self.name = None
- self._objects = {keepalive_key(0):self}
+ self._objects = {keepalive_key(0): self}
self._needs_free = True
# Empty function object -- this is needed for casts
@@ -222,10 +222,8 @@
if self._argtypes_ is None:
self._argtypes_ = []
self._ptr = self._getfuncptr_fromaddress(self._argtypes_, restype)
- self._check_argtypes_for_fastpath()
return
-
# A callback into python
if callable(argument) and not argsl:
self.callable = argument
@@ -259,7 +257,7 @@
if (sys.platform == 'win32' and isinstance(argument, (int, long))
and argsl):
ffiargs, ffires = self._ffishapes(self._argtypes_, self._restype_)
- self._com_index = argument + 0x1000
+ self._com_index = argument + 0x1000
self.name = argsl.pop(0)
if argsl:
self.paramflags = argsl.pop(0)
@@ -281,6 +279,7 @@
except SystemExit as e:
handle_system_exit(e)
raise
+
return f
def __call__(self, *args, **kwargs):
@@ -317,7 +316,7 @@
except:
exc_info = sys.exc_info()
traceback.print_tb(exc_info[2], file=sys.stderr)
- print >>sys.stderr, "%s: %s" % (exc_info[0].__name__, exc_info[1])
+ print >> sys.stderr, "%s: %s" % (exc_info[0].__name__, exc_info[1])
return 0
if self._restype_ is not None:
return res
@@ -328,7 +327,7 @@
# really slow". Now we don't worry that much about slowness
# of ctypes, and it's strange to get warnings for perfectly-
# legal code.
- #warnings.warn('C function without declared arguments called',
+ # warnings.warn('C function without declared arguments called',
# RuntimeWarning, stacklevel=2)
argtypes = []
@@ -337,7 +336,7 @@
if not args:
raise ValueError(
"native COM method call without 'this' parameter"
- )
+ )
thisvalue = args[0]
thisarg = cast(thisvalue, POINTER(POINTER(c_void_p)))
keepalives, newargs, argtypes, outargs, errcheckargs = (
@@ -366,7 +365,6 @@
return tuple(outargs)
def _call_funcptr(self, funcptr, *newargs):
-
if self._flags_ & _rawffi.FUNCFLAG_USE_ERRNO:
tmp = _rawffi.get_errno()
_rawffi.set_errno(get_errno())
@@ -431,7 +429,7 @@
ffiargs = [argtype.get_ffi_argtype() for argtype in argtypes]
ffires = restype.get_ffi_argtype()
return _ffi.FuncPtr.fromaddr(ptr, '', ffiargs, ffires, self._flags_)
-
+
cdll = self.dll._handle
try:
ffi_argtypes = [argtype.get_ffi_argtype() for argtype in argtypes]
@@ -450,7 +448,7 @@
# funcname -> _funcname@<n>
# where n is 0, 4, 8, 12, ..., 128
for i in range(33):
- mangled_name = "_%s@%d" % (self.name, i*4)
+ mangled_name = "_%s@%d" % (self.name, i * 4)
try:
return cdll.getfunc(mangled_name,
ffi_argtypes, ffi_restype,
@@ -492,7 +490,7 @@
for argtype, arg in zip(argtypes, args):
param = argtype.from_param(arg)
_type_ = getattr(argtype, '_type_', None)
- if _type_ == 'P': # special-case for c_void_p
+ if _type_ == 'P': # special-case for c_void_p
param = param._get_buffer_value()
elif self._is_primitive(argtype):
param = param.value
@@ -668,69 +666,11 @@
self._needs_free = False
-def make_fastpath_subclass(CFuncPtr):
- if CFuncPtr._is_fastpath:
- return CFuncPtr
- #
- try:
- return make_fastpath_subclass.memo[CFuncPtr]
- except KeyError:
- pass
-
- class CFuncPtrFast(CFuncPtr):
-
- _is_fastpath = True
- _slowpath_allowed = True # set to False by tests
-
- @classmethod
- def enable_fastpath_maybe(cls, obj):
- if (obj.callable is None and
- obj._com_index is None):
- obj.__class__ = cls
-
- def __rollback(self):
- assert self._slowpath_allowed
- self.__class__ = CFuncPtr
-
- # disable the fast path if we reset argtypes
- def _setargtypes(self, argtypes):
- self.__rollback()
- self._setargtypes(argtypes)
- argtypes = property(CFuncPtr._getargtypes, _setargtypes)
-
- def _setcallable(self, func):
- self.__rollback()
- self.callable = func
- callable = property(lambda x: None, _setcallable)
-
- def _setcom_index(self, idx):
- self.__rollback()
- self._com_index = idx
- _com_index = property(lambda x: None, _setcom_index)
-
- def __call__(self, *args):
- thisarg = None
- argtypes = self._argtypes_
- restype = self._restype_
- funcptr = self._getfuncptr(argtypes, restype, thisarg)
- try:
- result = self._call_funcptr(funcptr, *args)
- result, _ = self._do_errcheck(result, args)
- except (TypeError, ArgumentError, UnicodeDecodeError):
- assert self._slowpath_allowed
- return CFuncPtr.__call__(self, *args)
- return result
-
- make_fastpath_subclass.memo[CFuncPtr] = CFuncPtrFast
- return CFuncPtrFast
-make_fastpath_subclass.memo = {}
-
-
def handle_system_exit(e):
# issue #1194: if we get SystemExit here, then exit the interpreter.
# Highly obscure imho but some people seem to depend on it.
if sys.flags.inspect:
- return # Don't exit if -i flag was given.
+ return # Don't exit if -i flag was given.
else:
code = e.code
if isinstance(code, int):
diff --git a/pypy/module/test_lib_pypy/ctypes_tests/README b/pypy/module/test_lib_pypy/ctypes_tests/README
new file mode 100644
--- /dev/null
+++ b/pypy/module/test_lib_pypy/ctypes_tests/README
@@ -0,0 +1,8 @@
+-------Ctypes tests------
+
+Unlike the other tests in the PyPy sources, these tests are assumed to run after the translation is complete.
+Therefore, using the resulting binary, you can then call, for example:
+
+/path/to/your_modified_pypy_binary pytest.py pypy/module/test_lib_pypy/ctypes_tests/test_libc.py
+
+This also applies to any other test in ctypes_tests.
\ No newline at end of file
diff --git a/pypy/module/test_lib_pypy/ctypes_tests/test_fastpath.py b/pypy/module/test_lib_pypy/ctypes_tests/test_fastpath.py
deleted file mode 100644
--- a/pypy/module/test_lib_pypy/ctypes_tests/test_fastpath.py
+++ /dev/null
@@ -1,128 +0,0 @@
-from ctypes import CDLL, POINTER, pointer, c_byte, c_int, c_char_p, CFUNCTYPE, c_void_p, c_size_t
-import sys
-import py
-from support import BaseCTypesTestChecker
-
-class MyCDLL(CDLL):
- def __getattr__(self, attr):
- fn = self[attr] # this way it's not cached as an attribute
- fn._slowpath_allowed = False
- return fn
-
-def setup_module(mod):
- import conftest
- _ctypes_test = str(conftest.sofile)
- mod.dll = MyCDLL(_ctypes_test) # slowpath not allowed
- mod.dll2 = CDLL(_ctypes_test) # slowpath allowed
-
-
-class TestFastpath(BaseCTypesTestChecker):
-
- def test_fastpath_forbidden(self):
- def myfunc():
- pass
- #
- tf_b = dll.tf_b
- tf_b.restype = c_byte
- #
- # so far, it's still using the slowpath
- assert not tf_b._is_fastpath
- tf_b.callable = myfunc
- tf_b.argtypes = (c_byte,)
- # errcheck prevented the fastpath to kick in
- assert not tf_b._is_fastpath
- #
- del tf_b.callable
- tf_b.argtypes = (c_byte,) # try to re-enable the fastpath
- assert tf_b._is_fastpath
- #
- assert not tf_b._slowpath_allowed
- py.test.raises(AssertionError, "tf_b.callable = myfunc")
- py.test.raises(AssertionError, "tf_b('aaa')") # force a TypeError
-
- def test_simple_args(self):
- tf_b = dll.tf_b
- tf_b.restype = c_byte
- tf_b.argtypes = (c_byte,)
- assert tf_b(-126) == -42
-
- def test_from_cfunctype(self):
- from _ctypes import _memmove_addr
- functype = CFUNCTYPE(c_void_p, c_void_p, c_void_p, c_size_t)
- my_memmove = functype(_memmove_addr)
- assert my_memmove._is_fastpath
-
- def test_undeclared_restype(self):
- # make sure we get a fresh function
- try:
- del dll.tf_i
- except AttributeError:
- pass
- tf_i = dll.tf_i
- assert not tf_i._is_fastpath
- tf_i.argtypes = (c_int,)
- assert tf_i._is_fastpath
- assert tf_i(12) == 4
-
- def test_pointer_args(self):
- f = dll._testfunc_p_p
- f.restype = POINTER(c_int)
- f.argtypes = [POINTER(c_int)]
- v = c_int(42)
- result = f(pointer(v))
- assert type(result) == POINTER(c_int)
- assert result.contents.value == 42
-
- def test_simple_pointer_args(self):
- f = dll.my_strchr
- f.argtypes = [c_char_p, c_int]
- f.restype = c_char_p
- mystr = c_char_p("abcd")
- result = f(mystr, ord("b"))
- assert result == "bcd"
-
- def test_strings(self):
- f = dll.my_strchr
- f.argtypes = [c_char_p, c_int]
- f.restype = c_char_p
- result = f("abcd", ord("b"))
- assert result == "bcd"
-
- def test_errcheck(self):
- def errcheck(result, func, args):
- return 'hello'
- tf_b = dll.tf_b
- tf_b.restype = c_byte
- tf_b.argtypes = (c_byte,)
- tf_b.errcheck = errcheck
- assert tf_b(-126) == 'hello'
-
- def test_array_to_ptr(self):
- ARRAY = c_int * 8
- func = dll._testfunc_ai8
- func.restype = POINTER(c_int)
- func.argtypes = [ARRAY]
- array = ARRAY(1, 2, 3, 4, 5, 6, 7, 8)
- ptr = func(array)
- assert ptr[0] == 1
- assert ptr[7] == 8
-
-
-class TestFallbackToSlowpath(BaseCTypesTestChecker):
-
- def test_argtypes_is_None(self):
- tf_b = dll2.tf_b
- tf_b.restype = c_byte
- tf_b.argtypes = (c_char_p,) # this is intentionally wrong
- tf_b.argtypes = None # kill the fast path
- assert not tf_b._is_fastpath
- assert tf_b(-126) == -42
-
- def test_callable_is_None(self):
- tf_b = dll2.tf_b
- tf_b.restype = c_byte
- tf_b.argtypes = (c_byte,)
- tf_b.callable = lambda x: x+1
- assert not tf_b._is_fastpath
- assert tf_b(-126) == -125
- tf_b.callable = None
diff --git a/pypy/module/test_lib_pypy/ctypes_tests/test_functions.py b/pypy/module/test_lib_pypy/ctypes_tests/test_functions.py
--- a/pypy/module/test_lib_pypy/ctypes_tests/test_functions.py
+++ b/pypy/module/test_lib_pypy/ctypes_tests/test_functions.py
@@ -478,7 +478,7 @@
raises(ArgumentError, lambda: callback((1, 2, 3, 4), POINT()))
def test_argument_conversion_and_checks(self):
- py.test.skip("XXX currently broken on PyPy, sorry")
+ #This test is designed to check for segfaults if the wrong type of argument is passed as parameter
strlen = dll.my_strchr
strlen.argtypes = [c_char_p, c_int]
strlen.restype = c_char_p
More information about the pypy-commit
mailing list