Author: Matti Picus <matti.pi...@gmail.com> Branch: py3.5 Changeset: r95049:f7324252bc6b Date: 2018-08-31 09:05 +0200 http://bitbucket.org/pypy/pypy/changeset/f7324252bc6b/
Log: merge default 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 @@ -292,9 +292,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) @@ -305,7 +306,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): @@ -375,15 +377,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): @@ -471,9 +475,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) @@ -483,7 +488,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) @@ -553,13 +559,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]) _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit