[pypy-commit] pypy default: Issue #2813
arigo
pypy.commits at gmail.com
Fri Apr 27 22:25:36 EDT 2018
Author: Armin Rigo <arigo at tunes.org>
Branch:
Changeset: r94456:4a06e23782cf
Date: 2018-04-28 04:24 +0200
http://bitbucket.org/pypy/pypy/changeset/4a06e23782cf/
Log: Issue #2813
Fix for ctypes: doing some operations before setting the _fields_ of
a Structure would make and cache an _ffiargtype that says "opaque".
diff --git a/lib_pypy/_ctypes/array.py b/lib_pypy/_ctypes/array.py
--- a/lib_pypy/_ctypes/array.py
+++ b/lib_pypy/_ctypes/array.py
@@ -82,8 +82,11 @@
def _CData_output(self, resarray, base=None, index=-1):
from _rawffi.alt import types
# If a char_p or unichar_p is received, skip the string interpretation
- if base._ffiargtype != types.Pointer(types.char_p) and \
- base._ffiargtype != types.Pointer(types.unichar_p):
+ try:
+ deref = type(base)._deref_ffiargtype()
+ except AttributeError:
+ deref = None
+ if deref != types.char_p and deref != types.unichar_p:
# this seems to be a string if we're array of char, surprise!
from ctypes import c_char, c_wchar
if self._type_ is c_char:
@@ -120,6 +123,12 @@
value = self(*value)
return _CDataMeta.from_param(self, value)
+ def _build_ffiargtype(self):
+ return _ffi.types.Pointer(self._type_.get_ffi_argtype())
+
+ def _deref_ffiargtype(self):
+ return self._type_.get_ffi_argtype()
+
def array_get_slice_params(self, index):
if hasattr(self, '_length_'):
start, stop, step = index.indices(self._length_)
@@ -248,6 +257,5 @@
_type_ = base
)
cls = ArrayMeta(name, (Array,), tpdict)
- cls._ffiargtype = _ffi.types.Pointer(base.get_ffi_argtype())
ARRAY_CACHE[key] = cls
return cls
diff --git a/lib_pypy/_ctypes/basics.py b/lib_pypy/_ctypes/basics.py
--- a/lib_pypy/_ctypes/basics.py
+++ b/lib_pypy/_ctypes/basics.py
@@ -49,10 +49,13 @@
else:
return self.from_param(as_parameter)
+ def _build_ffiargtype(self):
+ return _shape_to_ffi_type(self._ffiargshape_)
+
def get_ffi_argtype(self):
if self._ffiargtype:
return self._ffiargtype
- self._ffiargtype = _shape_to_ffi_type(self._ffiargshape_)
+ self._ffiargtype = self._build_ffiargtype()
return self._ffiargtype
def _CData_output(self, resbuffer, base=None, index=-1):
diff --git a/lib_pypy/_ctypes/pointer.py b/lib_pypy/_ctypes/pointer.py
--- a/lib_pypy/_ctypes/pointer.py
+++ b/lib_pypy/_ctypes/pointer.py
@@ -70,7 +70,12 @@
self._ffiarray = ffiarray
self.__init__ = __init__
self._type_ = TP
- self._ffiargtype = _ffi.types.Pointer(TP.get_ffi_argtype())
+
+ def _build_ffiargtype(self):
+ return _ffi.types.Pointer(self._type_.get_ffi_argtype())
+
+ def _deref_ffiargtype(self):
+ return self._type_.get_ffi_argtype()
from_address = cdata_from_address
diff --git a/lib_pypy/_ctypes/structure.py b/lib_pypy/_ctypes/structure.py
--- a/lib_pypy/_ctypes/structure.py
+++ b/lib_pypy/_ctypes/structure.py
@@ -160,6 +160,10 @@
raise AttributeError("_fields_ is final")
if self in [f[1] for f in value]:
raise AttributeError("Structure or union cannot contain itself")
+ if self._ffiargtype is not None:
+ raise NotImplementedError("Too late to set _fields_: we already "
+ "said to libffi that the structure type %s is opaque"
+ % (self,))
names_and_fields(
self,
value, self.__bases__[0],
diff --git a/pypy/module/test_lib_pypy/ctypes_tests/test_pointers.py b/pypy/module/test_lib_pypy/ctypes_tests/test_pointers.py
--- a/pypy/module/test_lib_pypy/ctypes_tests/test_pointers.py
+++ b/pypy/module/test_lib_pypy/ctypes_tests/test_pointers.py
@@ -272,3 +272,18 @@
base = cast(d, c_void_p).value
for i in [0, 1, 4, 1444, -10293]:
assert cast(byref(c, i), c_void_p).value == base + i
+
+ def test_issue2813_fix(self):
+ class C(Structure):
+ pass
+ POINTER(C)
+ C._fields_ = [('x', c_int)]
+ ffitype = C.get_ffi_argtype()
+ assert C.get_ffi_argtype() is ffitype
+ assert ffitype.sizeof() == sizeof(c_int)
+
+ def test_issue2813_cant_change_fields_after_get_ffi_argtype(self):
+ class C(Structure):
+ pass
+ ffitype = C.get_ffi_argtype()
+ raises(NotImplementedError, "C._fields_ = [('x', c_int)]")
More information about the pypy-commit
mailing list