https://github.com/python/cpython/commit/cef0a90d8f3a94aa534593f39b4abf98165675b9
commit: cef0a90d8f3a94aa534593f39b4abf98165675b9
branch: main
author: Melissa0x1f992 <[email protected]>
committer: encukou <[email protected]>
date: 2024-12-10T13:13:11+01:00
summary:

gh-126937: ctypes: fix TypeError when a field's size is >65535 bytes (GH-126938)


Co-authored-by: Peter Bierma <[email protected]>
Co-authored-by: Terry Jan Reedy <[email protected]>
Co-authored-by: Petr Viktorin <[email protected]>

files:
A 
Misc/NEWS.d/next/Core_and_Builtins/2024-11-17-21-35-55.gh-issue-126937.qluVM0.rst
M Lib/test/test_ctypes/test_struct_fields.py
M Modules/_ctypes/cfield.c
M Modules/_ctypes/stgdict.c

diff --git a/Lib/test/test_ctypes/test_struct_fields.py 
b/Lib/test/test_ctypes/test_struct_fields.py
index b5e165f3bae929..1b3e64efd410b8 100644
--- a/Lib/test/test_ctypes/test_struct_fields.py
+++ b/Lib/test/test_ctypes/test_struct_fields.py
@@ -1,4 +1,5 @@
 import unittest
+import sys
 from ctypes import Structure, Union, sizeof, c_char, c_int
 from ._support import (CField, Py_TPFLAGS_DISALLOW_INSTANTIATION,
                        Py_TPFLAGS_IMMUTABLETYPE)
@@ -75,6 +76,28 @@ def __init_subclass__(cls, **kwargs):
                                     'ctypes state is not initialized'):
             class Subclass(BrokenStructure): ...
 
+    def test_max_field_size_gh126937(self):
+        # Classes for big structs should be created successfully.
+        # (But they most likely can't be instantiated.)
+        # Here we test the exact limit: the number of *bits* must fit
+        # in Py_ssize_t.
+
+        class X(self.cls):
+            _fields_ = [('char', c_char),]
+        max_field_size = sys.maxsize // 8
+
+        class Y(self.cls):
+            _fields_ = [('largeField', X * max_field_size)]
+        class Z(self.cls):
+            _fields_ = [('largeField', c_char * max_field_size)]
+
+        with self.assertRaises(ValueError):
+            class TooBig(self.cls):
+                _fields_ = [('largeField', X * (max_field_size + 1))]
+        with self.assertRaises(ValueError):
+            class TooBig(self.cls):
+                _fields_ = [('largeField', c_char * (max_field_size + 1))]
+
     # __set__ and __get__ should raise a TypeError in case their self
     # argument is not a ctype instance.
     def test___set__(self):
diff --git 
a/Misc/NEWS.d/next/Core_and_Builtins/2024-11-17-21-35-55.gh-issue-126937.qluVM0.rst
 
b/Misc/NEWS.d/next/Core_and_Builtins/2024-11-17-21-35-55.gh-issue-126937.qluVM0.rst
new file mode 100644
index 00000000000000..8d7da0d4107021
--- /dev/null
+++ 
b/Misc/NEWS.d/next/Core_and_Builtins/2024-11-17-21-35-55.gh-issue-126937.qluVM0.rst
@@ -0,0 +1,3 @@
+Fix :exc:`TypeError` when a :class:`ctypes.Structure` has a field size
+that doesn't fit into an unsigned 16-bit integer.
+Instead, the maximum number of *bits* is :data:`sys.maxsize`.
diff --git a/Modules/_ctypes/cfield.c b/Modules/_ctypes/cfield.c
index 3220852c8398e0..2b9e8a1a10d6f5 100644
--- a/Modules/_ctypes/cfield.c
+++ b/Modules/_ctypes/cfield.c
@@ -110,10 +110,16 @@ PyCField_new_impl(PyTypeObject *type, PyObject *name, 
PyObject *proto,
         goto error;
     }
 
-    Py_ssize_t bit_size = NUM_BITS(size);
-    if (bit_size) {
+    if (bit_size_obj != Py_None) {
+#ifdef Py_DEBUG
+        Py_ssize_t bit_size = NUM_BITS(size);
         assert(bit_size > 0);
         assert(bit_size <= info->size * 8);
+        // Currently, the bit size is specified redundantly
+        // in NUM_BITS(size) and bit_size_obj.
+        // Verify that they match.
+        assert(PyLong_AsSsize_t(bit_size_obj) == bit_size);
+#endif
         switch(info->ffi_type_pointer.type) {
             case FFI_TYPE_UINT8:
             case FFI_TYPE_UINT16:
diff --git a/Modules/_ctypes/stgdict.c b/Modules/_ctypes/stgdict.c
index 5dbbe0b3285d58..5ca5b62427600d 100644
--- a/Modules/_ctypes/stgdict.c
+++ b/Modules/_ctypes/stgdict.c
@@ -292,7 +292,7 @@ PyCStructUnionType_update_stginfo(PyObject *type, PyObject 
*fields, int isStruct
     if (!tmp) {
         goto error;
     }
-    Py_ssize_t total_align = PyLong_AsInt(tmp);
+    Py_ssize_t total_align = PyLong_AsSsize_t(tmp);
     Py_DECREF(tmp);
     if (total_align < 0) {
         if (!PyErr_Occurred()) {
@@ -306,7 +306,7 @@ PyCStructUnionType_update_stginfo(PyObject *type, PyObject 
*fields, int isStruct
     if (!tmp) {
         goto error;
     }
-    Py_ssize_t total_size = PyLong_AsInt(tmp);
+    Py_ssize_t total_size = PyLong_AsSsize_t(tmp);
     Py_DECREF(tmp);
     if (total_size < 0) {
         if (!PyErr_Occurred()) {

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: [email protected]

Reply via email to