mirror of
https://github.com/python/cpython.git
synced 2026-01-06 15:32:22 +00:00
[3.11] gh-62260: Fix ctypes.Structure subclassing with multiple layers (GH-13374) (GH-113624)
The length field of StgDictObject for Structure class contains now
the total number of items in ffi_type_pointer.elements (excluding
the trailing null).
The old behavior of using the number of elements in the parent class can
cause the array to be truncated when it is copied, especially when there
are multiple layers of subclassing.
(cherry picked from commit 5f3cc90a12)
Co-authored-by: Jeffrey Kintscher <49998481+websurfer5@users.noreply.github.com>
This commit is contained in:
parent
5169113379
commit
36153494f1
4 changed files with 71 additions and 6 deletions
|
|
@ -1,4 +1,6 @@
|
|||
import platform
|
||||
from platform import architecture as _architecture
|
||||
import struct
|
||||
import sys
|
||||
import unittest
|
||||
from ctypes.test import need_symbol
|
||||
|
|
@ -7,6 +9,7 @@
|
|||
c_uint8, c_uint16, c_uint32,
|
||||
c_short, c_ushort, c_int, c_uint,
|
||||
c_long, c_ulong, c_longlong, c_ulonglong, c_float, c_double)
|
||||
from ctypes.util import find_library
|
||||
from struct import calcsize
|
||||
import _ctypes_test
|
||||
from test import support
|
||||
|
|
@ -479,6 +482,66 @@ class X(Structure):
|
|||
self.assertEqual(s.first, got.first)
|
||||
self.assertEqual(s.second, got.second)
|
||||
|
||||
def _test_issue18060(self, Vector):
|
||||
# The call to atan2() should succeed if the
|
||||
# class fields were correctly cloned in the
|
||||
# subclasses. Otherwise, it will segfault.
|
||||
if sys.platform == 'win32':
|
||||
libm = CDLL(find_library('msvcrt.dll'))
|
||||
else:
|
||||
libm = CDLL(find_library('m'))
|
||||
|
||||
libm.atan2.argtypes = [Vector]
|
||||
libm.atan2.restype = c_double
|
||||
|
||||
arg = Vector(y=0.0, x=-1.0)
|
||||
self.assertAlmostEqual(libm.atan2(arg), 3.141592653589793)
|
||||
|
||||
@unittest.skipIf(_architecture() == ('64bit', 'WindowsPE'), "can't test Windows x64 build")
|
||||
@unittest.skipUnless(sys.byteorder == 'little', "can't test on this platform")
|
||||
def test_issue18060_a(self):
|
||||
# This test case calls
|
||||
# PyCStructUnionType_update_stgdict() for each
|
||||
# _fields_ assignment, and PyCStgDict_clone()
|
||||
# for the Mid and Vector class definitions.
|
||||
class Base(Structure):
|
||||
_fields_ = [('y', c_double),
|
||||
('x', c_double)]
|
||||
class Mid(Base):
|
||||
pass
|
||||
Mid._fields_ = []
|
||||
class Vector(Mid): pass
|
||||
self._test_issue18060(Vector)
|
||||
|
||||
@unittest.skipIf(_architecture() == ('64bit', 'WindowsPE'), "can't test Windows x64 build")
|
||||
@unittest.skipUnless(sys.byteorder == 'little', "can't test on this platform")
|
||||
def test_issue18060_b(self):
|
||||
# This test case calls
|
||||
# PyCStructUnionType_update_stgdict() for each
|
||||
# _fields_ assignment.
|
||||
class Base(Structure):
|
||||
_fields_ = [('y', c_double),
|
||||
('x', c_double)]
|
||||
class Mid(Base):
|
||||
_fields_ = []
|
||||
class Vector(Mid):
|
||||
_fields_ = []
|
||||
self._test_issue18060(Vector)
|
||||
|
||||
@unittest.skipIf(_architecture() == ('64bit', 'WindowsPE'), "can't test Windows x64 build")
|
||||
@unittest.skipUnless(sys.byteorder == 'little', "can't test on this platform")
|
||||
def test_issue18060_c(self):
|
||||
# This test case calls
|
||||
# PyCStructUnionType_update_stgdict() for each
|
||||
# _fields_ assignment.
|
||||
class Base(Structure):
|
||||
_fields_ = [('y', c_double)]
|
||||
class Mid(Base):
|
||||
_fields_ = []
|
||||
class Vector(Mid):
|
||||
_fields_ = [('x', c_double)]
|
||||
self._test_issue18060(Vector)
|
||||
|
||||
def test_array_in_struct(self):
|
||||
# See bpo-22273
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,2 @@
|
|||
Fixed a class inheritance issue that can cause segfaults when deriving two or more levels of subclasses from a base class of Structure or Union.
|
||||
|
||||
|
|
@ -4387,10 +4387,10 @@ _init_pos_args(PyObject *self, PyTypeObject *type,
|
|||
return index;
|
||||
}
|
||||
|
||||
for (i = 0;
|
||||
i < dict->length && (i+index) < PyTuple_GET_SIZE(args);
|
||||
for (i = index;
|
||||
i < dict->length && i < PyTuple_GET_SIZE(args);
|
||||
++i) {
|
||||
PyObject *pair = PySequence_GetItem(fields, i);
|
||||
PyObject *pair = PySequence_GetItem(fields, i - index);
|
||||
PyObject *name, *val;
|
||||
int res;
|
||||
if (!pair)
|
||||
|
|
@ -4400,7 +4400,7 @@ _init_pos_args(PyObject *self, PyTypeObject *type,
|
|||
Py_DECREF(pair);
|
||||
return -1;
|
||||
}
|
||||
val = PyTuple_GET_ITEM(args, i + index);
|
||||
val = PyTuple_GET_ITEM(args, i);
|
||||
if (kwds) {
|
||||
res = PyDict_Contains(kwds, name);
|
||||
if (res != 0) {
|
||||
|
|
@ -4421,7 +4421,7 @@ _init_pos_args(PyObject *self, PyTypeObject *type,
|
|||
if (res == -1)
|
||||
return -1;
|
||||
}
|
||||
return index + dict->length;
|
||||
return dict->length;
|
||||
}
|
||||
|
||||
static int
|
||||
|
|
|
|||
|
|
@ -660,7 +660,7 @@ PyCStructUnionType_update_stgdict(PyObject *type, PyObject *fields, int isStruct
|
|||
|
||||
stgdict->size = size;
|
||||
stgdict->align = total_align;
|
||||
stgdict->length = len; /* ADD ffi_ofs? */
|
||||
stgdict->length = ffi_ofs + len;
|
||||
|
||||
/*
|
||||
* On Arm platforms, structs with at most 4 elements of any floating point
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue