[pypy-commit] pypy unicode-utf8-py3: merge py3.5 into branch
mattip
pypy.commits at gmail.com
Fri Aug 31 03:08:34 EDT 2018
Author: Matti Picus <matti.picus at gmail.com>
Branch: unicode-utf8-py3
Changeset: r95050:e94950decff4
Date: 2018-08-31 09:06 +0200
http://bitbucket.org/pypy/pypy/changeset/e94950decff4/
Log: merge py3.5 into branch
diff --git a/lib_pypy/cffi/_cffi_include.h b/lib_pypy/cffi/_cffi_include.h
--- a/lib_pypy/cffi/_cffi_include.h
+++ b/lib_pypy/cffi/_cffi_include.h
@@ -8,20 +8,43 @@
the same works for the other two macros. Py_DEBUG implies them,
but not the other way around.
- Issue #350 is still open: on Windows, the code here causes it to link
- with PYTHON36.DLL (for example) instead of PYTHON3.DLL. A fix was
- attempted in 164e526a5515 and 14ce6985e1c3, but reverted: virtualenv
- does not make PYTHON3.DLL available, and so the "correctly" compiled
- version would not run inside a virtualenv. We will re-apply the fix
- after virtualenv has been fixed for some time. For explanation, see
- issue #355. For a workaround if you want PYTHON3.DLL and don't worry
- about virtualenv, see issue #350. See also 'py_limited_api' in
- setuptools_ext.py.
+ The implementation is messy (issue #350): on Windows, with _MSC_VER,
+ we have to define Py_LIMITED_API even before including pyconfig.h.
+ In that case, we guess what pyconfig.h will do to the macros above,
+ and check our guess after the #include.
+
+ Note that on Windows, with CPython 3.x, you need virtualenv version
+ >= 16.0.0. Older versions don't copy PYTHON3.DLL. As a workaround
+ you can remove the definition of Py_LIMITED_API here.
+
+ See also 'py_limited_api' in cffi/setuptools_ext.py.
*/
#if !defined(_CFFI_USE_EMBEDDING) && !defined(Py_LIMITED_API)
-# include <pyconfig.h>
-# if !defined(Py_DEBUG) && !defined(Py_TRACE_REFS) && !defined(Py_REF_DEBUG)
-# define Py_LIMITED_API
+# ifdef _MSC_VER
+# if !defined(_DEBUG) && !defined(Py_DEBUG) && !defined(Py_TRACE_REFS) && !defined(Py_REF_DEBUG)
+# define Py_LIMITED_API
+# endif
+# include <pyconfig.h>
+ /* sanity-check: Py_LIMITED_API will cause crashes if any of these
+ are also defined. Normally, the Python file PC/pyconfig.h does not
+ cause any of these to be defined, with the exception that _DEBUG
+ causes Py_DEBUG. Double-check that. */
+# ifdef Py_LIMITED_API
+# if defined(Py_DEBUG)
+# error "pyconfig.h unexpectedly defines Py_DEBUG, but Py_LIMITED_API is set"
+# endif
+# if defined(Py_TRACE_REFS)
+# error "pyconfig.h unexpectedly defines Py_TRACE_REFS, but Py_LIMITED_API is set"
+# endif
+# if defined(Py_REF_DEBUG)
+# error "pyconfig.h unexpectedly defines Py_REF_DEBUG, but Py_LIMITED_API is set"
+# endif
+# endif
+# else
+# include <pyconfig.h>
+# if !defined(Py_DEBUG) && !defined(Py_TRACE_REFS) && !defined(Py_REF_DEBUG)
+# define Py_LIMITED_API
+# endif
# endif
#endif
diff --git a/lib_pypy/cffi/backend_ctypes.py b/lib_pypy/cffi/backend_ctypes.py
--- a/lib_pypy/cffi/backend_ctypes.py
+++ b/lib_pypy/cffi/backend_ctypes.py
@@ -636,6 +636,10 @@
if isinstance(init, bytes):
init = [init[i:i+1] for i in range(len(init))]
else:
+ if isinstance(init, CTypesGenericArray):
+ if (len(init) != len(blob) or
+ not isinstance(init, CTypesArray)):
+ raise TypeError("length/type mismatch: %s" % (init,))
init = tuple(init)
if len(init) > len(blob):
raise IndexError("too many initializers")
diff --git a/lib_pypy/cffi/setuptools_ext.py b/lib_pypy/cffi/setuptools_ext.py
--- a/lib_pypy/cffi/setuptools_ext.py
+++ b/lib_pypy/cffi/setuptools_ext.py
@@ -81,13 +81,8 @@
it doesn't so far, creating troubles. That's why we check
for "not hasattr(sys, 'gettotalrefcount')" (the 2.7 compatible equivalent
of 'd' not in sys.abiflags). (http://bugs.python.org/issue28401)
-
- On Windows, it's better not to use py_limited_api until issue #355
- can be resolved (by having virtualenv copy PYTHON3.DLL). See also
- the start of _cffi_include.h.
"""
- if ('py_limited_api' not in kwds and not hasattr(sys, 'gettotalrefcount')
- and sys.platform != 'win32'):
+ if 'py_limited_api' not in kwds and not hasattr(sys, 'gettotalrefcount'):
import setuptools
try:
setuptools_major_version = int(setuptools.__version__.partition('.')[0])
diff --git a/pypy/module/_cffi_backend/ctypearray.py b/pypy/module/_cffi_backend/ctypearray.py
--- a/pypy/module/_cffi_backend/ctypearray.py
+++ b/pypy/module/_cffi_backend/ctypearray.py
@@ -104,7 +104,15 @@
return self.ctptr
def convert_from_object(self, cdata, w_ob):
- self.convert_array_from_object(cdata, w_ob)
+ if isinstance(w_ob, cdataobj.W_CData) and w_ob.ctype is self:
+ length = w_ob.get_array_length()
+ with w_ob as source:
+ source = rffi.cast(rffi.VOIDP, source)
+ target = rffi.cast(rffi.VOIDP, cdata)
+ size = rffi.cast(rffi.SIZE_T, self.ctitem.size * length)
+ rffi.c_memcpy(target, source, size)
+ else:
+ self.convert_array_from_object(cdata, w_ob)
def convert_to_object(self, cdata):
if self.length < 0:
diff --git a/pypy/module/_cffi_backend/ctypeobj.py b/pypy/module/_cffi_backend/ctypeobj.py
--- a/pypy/module/_cffi_backend/ctypeobj.py
+++ b/pypy/module/_cffi_backend/ctypeobj.py
@@ -51,9 +51,12 @@
def unpack_list_of_float_items(self, ptr, length):
return None
- def pack_list_of_items(self, cdata, w_ob):
+ def pack_list_of_items(self, cdata, w_ob, expected_length):
return False
+ def _within_bounds(self, actual_length, expected_length):
+ return expected_length < 0 or actual_length <= expected_length
+
def newp(self, w_init, allocator):
space = self.space
raise oefmt(space.w_TypeError,
@@ -102,6 +105,11 @@
# ctype 'A' must be a pointer to same type, not cdata
# 'B'", but with A=B, then give instead a different error
# message to try to clear up the confusion
+ if self is w_got.ctype:
+ raise oefmt(space.w_SystemError,
+ "initializer for ctype '%s' is correct, but we get "
+ "an internal mismatch--please report a bug",
+ self.name)
return oefmt(space.w_TypeError,
"initializer for ctype '%s' appears indeed to "
"be '%s', but the types are different (check "
diff --git a/pypy/module/_cffi_backend/ctypeprim.py b/pypy/module/_cffi_backend/ctypeprim.py
--- a/pypy/module/_cffi_backend/ctypeprim.py
+++ b/pypy/module/_cffi_backend/ctypeprim.py
@@ -288,9 +288,10 @@
return res
return None
- def pack_list_of_items(self, cdata, w_ob):
+ def pack_list_of_items(self, cdata, w_ob, expected_length):
int_list = self.space.listview_int(w_ob)
- if int_list is not None:
+ if (int_list is not None and
+ self._within_bounds(len(int_list), expected_length)):
if self.size == rffi.sizeof(rffi.LONG): # fastest path
from rpython.rlib.rrawarray import copy_list_to_raw_array
cdata = rffi.cast(rffi.LONGP, cdata)
@@ -301,7 +302,8 @@
if overflowed != 0:
self._overflow(self.space.newint(overflowed))
return True
- return W_CTypePrimitive.pack_list_of_items(self, cdata, w_ob)
+ return W_CTypePrimitive.pack_list_of_items(self, cdata, w_ob,
+ expected_length)
class W_CTypePrimitiveUnsigned(W_CTypePrimitive):
@@ -371,15 +373,17 @@
return res
return None
- def pack_list_of_items(self, cdata, w_ob):
+ def pack_list_of_items(self, cdata, w_ob, expected_length):
int_list = self.space.listview_int(w_ob)
- if int_list is not None:
+ if (int_list is not None and
+ self._within_bounds(len(int_list), expected_length)):
overflowed = misc.pack_list_to_raw_array_bounds_unsigned(
int_list, cdata, self.size, self.vrangemax)
if overflowed != 0:
self._overflow(self.space.newint(overflowed))
return True
- return W_CTypePrimitive.pack_list_of_items(self, cdata, w_ob)
+ return W_CTypePrimitive.pack_list_of_items(self, cdata, w_ob,
+ expected_length)
class W_CTypePrimitiveBool(W_CTypePrimitiveUnsigned):
@@ -467,9 +471,10 @@
return res
return None
- def pack_list_of_items(self, cdata, w_ob):
+ def pack_list_of_items(self, cdata, w_ob, expected_length):
float_list = self.space.listview_float(w_ob)
- if float_list is not None:
+ if (float_list is not None and
+ self._within_bounds(len(float_list), expected_length)):
if self.size == rffi.sizeof(rffi.DOUBLE): # fastest path
from rpython.rlib.rrawarray import copy_list_to_raw_array
cdata = rffi.cast(rffi.DOUBLEP, cdata)
@@ -479,7 +484,8 @@
misc.pack_float_list_to_raw_array(float_list, cdata,
rffi.FLOAT, rffi.FLOATP)
return True
- return W_CTypePrimitive.pack_list_of_items(self, cdata, w_ob)
+ return W_CTypePrimitive.pack_list_of_items(self, cdata, w_ob,
+ expected_length)
def unpack_ptr(self, w_ctypeptr, ptr, length):
result = self.unpack_list_of_float_items(ptr, length)
@@ -549,13 +555,15 @@
# 'list(array-of-longdouble)' returns a list of cdata objects,
# not a list of floats.
- def pack_list_of_items(self, cdata, w_ob):
+ def pack_list_of_items(self, cdata, w_ob, expected_length):
float_list = self.space.listview_float(w_ob)
- if float_list is not None:
+ if (float_list is not None and
+ self._within_bounds(len(float_list), expected_length)):
misc.pack_float_list_to_raw_array(float_list, cdata,
rffi.LONGDOUBLE, rffi.LONGDOUBLEP)
return True
- return W_CTypePrimitive.pack_list_of_items(self, cdata, w_ob)
+ return W_CTypePrimitive.pack_list_of_items(self, cdata, w_ob,
+ expected_length)
@jit.dont_look_inside
def nonzero(self, cdata):
diff --git a/pypy/module/_cffi_backend/ctypeptr.py b/pypy/module/_cffi_backend/ctypeptr.py
--- a/pypy/module/_cffi_backend/ctypeptr.py
+++ b/pypy/module/_cffi_backend/ctypeptr.py
@@ -58,7 +58,7 @@
def _convert_array_from_listview(self, cdata, lst_w):
space = self.space
- if self.length >= 0 and len(lst_w) > self.length:
+ if not self._within_bounds(len(lst_w), self.length):
raise oefmt(space.w_IndexError,
"too many initializers for '%s' (got %d)",
self.name, len(lst_w))
@@ -71,8 +71,8 @@
space = self.space
if (space.isinstance_w(w_ob, space.w_list) or
space.isinstance_w(w_ob, space.w_tuple)):
- if self.ctitem.pack_list_of_items(cdata, w_ob): # fast path
- pass
+ if self.ctitem.pack_list_of_items(cdata, w_ob, self.length):
+ pass # fast path
else:
self._convert_array_from_listview(cdata, space.listview(w_ob))
elif self.accept_str:
diff --git a/pypy/module/_cffi_backend/test/_backend_test_c.py b/pypy/module/_cffi_backend/test/_backend_test_c.py
--- a/pypy/module/_cffi_backend/test/_backend_test_c.py
+++ b/pypy/module/_cffi_backend/test/_backend_test_c.py
@@ -1862,7 +1862,7 @@
def test_newp_copying():
"""Test that we can do newp(<type>, <cdata of the given type>) for most
- types, with the exception of arrays, like in C.
+ types, including same-type arrays.
"""
BInt = new_primitive_type("int")
p = newp(new_pointer_type(BInt), cast(BInt, 42))
@@ -1891,8 +1891,9 @@
a1 = newp(BArray, [1, 2, 3, 4])
py.test.raises(TypeError, newp, BArray, a1)
BArray6 = new_array_type(new_pointer_type(BInt), 6)
- a1 = newp(BArray6, None)
- py.test.raises(TypeError, newp, BArray6, a1)
+ a1 = newp(BArray6, [10, 20, 30])
+ a2 = newp(BArray6, a1)
+ assert list(a2) == [10, 20, 30, 0, 0, 0]
#
s1 = newp(BStructPtr, [42])
s2 = newp(BStructPtr, s1[0])
diff --git a/pypy/module/_cffi_backend/test/test_fastpath.py b/pypy/module/_cffi_backend/test/test_fastpath.py
--- a/pypy/module/_cffi_backend/test/test_fastpath.py
+++ b/pypy/module/_cffi_backend/test/test_fastpath.py
@@ -267,3 +267,17 @@
assert lst == [1.25, -2.5, 3.75]
if not self.runappdirect:
assert self.get_count() == 1
+
+ def test_too_many_initializers(self):
+ import _cffi_backend
+ ffi = _cffi_backend.FFI()
+ raises(IndexError, ffi.new, "int[4]", [10, 20, 30, 40, 50])
+ raises(IndexError, ffi.new, "int[4]", tuple(range(999)))
+ raises(IndexError, ffi.new, "unsigned int[4]", [10, 20, 30, 40, 50])
+ raises(IndexError, ffi.new, "float[4]", [10, 20, 30, 40, 50])
+ raises(IndexError, ffi.new, "long double[4]", [10, 20, 30, 40, 50])
+ raises(IndexError, ffi.new, "char[4]", [10, 20, 30, 40, 50])
+ raises(IndexError, ffi.new, "wchar_t[4]", [10, 20, 30, 40, 50])
+ raises(IndexError, ffi.new, "_Bool[4]", [10, 20, 30, 40, 50])
+ raises(IndexError, ffi.new, "int[4][4]", [[3,4,5,6]] * 5)
+ raises(IndexError, ffi.new, "int[4][4]", [[3,4,5,6,7]] * 4)
diff --git a/pypy/module/_cffi_backend/test/test_ffi_obj.py b/pypy/module/_cffi_backend/test/test_ffi_obj.py
--- a/pypy/module/_cffi_backend/test/test_ffi_obj.py
+++ b/pypy/module/_cffi_backend/test/test_ffi_obj.py
@@ -572,3 +572,13 @@
assert len(z) == 2
assert ffi.cast("int *", z)[0] == 0x12345
assert list(z) == [u'\U00012345', u'\x00'] # maybe a 2-unichars str
+
+ def test_ffi_array_as_init(self):
+ import _cffi_backend as _cffi1_backend
+ ffi = _cffi1_backend.FFI()
+ p = ffi.new("int[4]", [10, 20, 30, 400])
+ q = ffi.new("int[4]", p)
+ assert list(q) == [10, 20, 30, 400]
+ raises(TypeError, ffi.new, "int[3]", p)
+ raises(TypeError, ffi.new, "int[5]", p)
+ raises(TypeError, ffi.new, "int16_t[4]", p)
diff --git a/pypy/module/test_lib_pypy/cffi_tests/cffi0/backend_tests.py b/pypy/module/test_lib_pypy/cffi_tests/cffi0/backend_tests.py
--- a/pypy/module/test_lib_pypy/cffi_tests/cffi0/backend_tests.py
+++ b/pypy/module/test_lib_pypy/cffi_tests/cffi0/backend_tests.py
@@ -1973,3 +1973,18 @@
assert seen[1] == 101
assert seen[2] == 202
assert seen[3] == 303
+
+ def test_ffi_array_as_init(self):
+ ffi = FFI(backend=self.Backend())
+ p = ffi.new("int[4]", [10, 20, 30, 400])
+ q = ffi.new("int[4]", p)
+ assert list(q) == [10, 20, 30, 400]
+ py.test.raises(TypeError, ffi.new, "int[3]", p)
+ py.test.raises(TypeError, ffi.new, "int[5]", p)
+ py.test.raises(TypeError, ffi.new, "int16_t[4]", p)
+ s = ffi.new("struct {int i[4];}*", {'i': p})
+ assert list(s.i) == [10, 20, 30, 400]
+
+ def test_too_many_initializers(self):
+ ffi = FFI(backend=self.Backend())
+ py.test.raises(IndexError, ffi.new, "int[4]", [10, 20, 30, 40, 50])
More information about the pypy-commit
mailing list