8000 gh-126937: ctypes: fix TypeError when a field's size is >65535 bytes … · python/cpython@cef0a90 · GitHub
[go: up one dir, main page]

Skip to content

Commit cef0a90

Browse files
Melissa0x1f992ZeroIntensityterryjreedyencukou
authored
gh-126937: ctypes: fix TypeError when a field's size is >65535 bytes (GH-126938)
Co-authored-by: Peter Bierma <zintensitydev@gmail.com> Co-authored-by: Terry Jan Reedy <tjreedy@udel.edu> Co-authored-by: Petr Viktorin <encukou@gmail.com>
1 parent f4b31ed commit cef0a90

File tree

4 files changed

+36
-4
lines changed

4 files changed

+36
-4
lines changed

Lib/test/test_ctypes/test_struct_fields.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import unittest
2+
import sys
23
from ctypes import Structure, Union, sizeof, c_char, c_int
34
from ._support import (CField, Py_TPFLAGS_DISALLOW_INSTANTIATION,
45
Py_TPFLAGS_IMMUTABLETYPE)
@@ -75,6 +76,28 @@ def __init_subclass__(cls, **kwargs):
7576
'ctypes state is not initialized'):
7677
class Subclass(BrokenStructure): ...
7778

79+
def test_max_field_size_gh126937(self):
80+
# Classes for big structs should be created successfully.
81+
# (But they most likely can't be instantiated.)
82+
# Here we test the exact limit: the number of *bits* must fit
83+
# in Py_ssize_t.
84+
85+
class X(self.cls):
86+
_fields_ = [('char', c_char),]
87+
max_field_size = sys.maxsize // 8
88+
89+
class Y(self.cls):
90+
_fields_ = [('largeField', X * max_field_size)]
91+
class Z(self.cls):
92+
_fields_ = [('largeField', c_char * max_field_size)]
93+
94+
with self.assertRaises(ValueError):
95+
class TooBig(self.cls):
96+
_fields_ = [('largeField', X * (max_field_size + 1))]
97+
with self.assertRaises(ValueError):
98+
class TooBig(self.cls):
99+
_fields_ = [('largeField', c_char * (max_field_size + 1))]
100+
78101
# __set__ and __get__ should raise a TypeError in case their self
79102
# argument is not a ctype instance.
80103
def test___set__(self):
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Fix :exc:`TypeError` when a :class:`ctypes.Structure` has a field size
2+
that doesn't fit into an unsigned 16-bit integer.
3+
Instead, the maximum number of *bits* is :data:`sys.maxsize`.

Modules/_ctypes/cfield.c

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -110,10 +110,16 @@ PyCField_new_impl(PyTypeObject *type, PyObject *name, PyObject *proto,
110110
goto error;
111111
}
112112

113-
Py_ssize_t bit_size = NUM_BITS(size);
114-
if (bit_size) {
113+
if (bit_size_obj != Py_None) {
114+
#ifdef Py_DEBUG
115+
Py_ssize_t bit_size = NUM_BITS(size);
115116
assert(bit_size > 0);
116117
assert(bit_size <= info->size * 8);
118+
// Currently, the bit size is specified redundantly
119+
// in NUM_BITS(size) and bit_size_obj.
120+
// Verify that they match.
121+
assert(PyLong_AsSsize_t(bit_size_obj) == bit_size);
122+
#endif
117123
switch(info->ffi_type_pointer.type) {
118124
case FFI_TYPE_UINT8:
119125
case FFI_TYPE_UINT16:

Modules/_ctypes/stgdict.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,7 @@ PyCStructUnionType_update_stginfo(PyObject *type, PyObject *fields, int isStruct
292292
if (!tmp) {
293293
goto error;
294294
}
295-
Py_ssize_t total_align = PyLong_AsInt(tmp);
295+
Py_ssize_t total_align = PyLong_AsSsize_t(tmp);
296296
Py_DECREF(tmp);
297297
if (total_align < 0) {
298298
if (!PyErr_Occurred()) {
@@ -306,7 +306,7 @@ PyCStructUnionType_update_stginfo(PyObject *type, PyObject *fields, int isStruct
306306
if (!tmp) {
307307
goto error;
308308
}
309-
Py_ssize_t total_size = PyLong_AsInt(tmp);
309+
Py_ssize_t total_size = PyLong_AsSsize_t(tmp);
310310
Py_DECREF(tmp);
311311
if (total_size < 0) {
312312
if (!PyErr_Occurred()) {

0 commit comments

Comments
 (0)
0