summaryrefslogtreecommitdiffstats
path: root/Lib/test
diff options
context:
space:
mode:
authorSerhiy Storchaka <storchaka@gmail.com>2024-01-05 22:52:41 (GMT)
committerGitHub <noreply@github.com>2024-01-05 22:52:41 (GMT)
commit6d9af666165a3a69618ee940631ca6600d2a2027 (patch)
tree670225dcd2dd874795f35a48fa0ede24694be4d9 /Lib/test
parente132751b49a720da97e969542d89258a914cfe94 (diff)
downloadcpython-6d9af666165a3a69618ee940631ca6600d2a2027.zip
cpython-6d9af666165a3a69618ee940631ca6600d2a2027.tar.gz
cpython-6d9af666165a3a69618ee940631ca6600d2a2027.tar.bz2
[3.12] gh-62260: Fix ctypes.Structure subclassing with multiple layers (GH-13374) (GH-113623)
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 5f3cc90a12d6df404fd6f48a0df1334902e271f2) Co-authored-by: Jeffrey Kintscher <49998481+websurfer5@users.noreply.github.com>
Diffstat (limited to 'Lib/test')
-rw-r--r--Lib/test/test_ctypes/test_structures.py64
1 files changed, 63 insertions, 1 deletions
diff --git a/Lib/test/test_ctypes/test_structures.py b/Lib/test/test_ctypes/test_structures.py
index 466bfcd..ce2d1b3 100644
--- a/Lib/test/test_ctypes/test_structures.py
+++ b/Lib/test/test_ctypes/test_structures.py
@@ -1,4 +1,6 @@
import platform
+from platform import architecture as _architecture
+import struct
import sys
import unittest
from test.test_ctypes import need_symbol
@@ -7,6 +9,7 @@ from ctypes import (CDLL, Array, Structure, Union, POINTER, sizeof, byref, align
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 collections import namedtuple
@@ -189,7 +192,6 @@ class StructureTestCase(unittest.TestCase):
self.assertEqual(sizeof(X), 10)
self.assertEqual(X.b.offset, 2)
- import struct
longlong_size = struct.calcsize("q")
longlong_align = struct.calcsize("bq") - longlong_size
@@ -480,6 +482,66 @@ class StructureTestCase(unittest.TestCase):
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