mirror of
https://github.com/python/cpython.git
synced 2025-08-31 05:58:33 +00:00
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>
This commit is contained in:
parent
f4b31edf2d
commit
cef0a90d8f
4 changed files with 36 additions and 4 deletions
|
@ -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 @@ class FieldsTestBase:
|
|||
'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):
|
||||
|
|
|
@ -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`.
|
|
@ -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:
|
||||
|
|
|
@ -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()) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue