From 3b4b56f46dbfc0c336a1f70704f127593ec1f4ce Mon Sep 17 00:00:00 2001 From: dura0ok Date: Tue, 22 Apr 2025 20:13:00 +0700 Subject: [PATCH] gh-132470: Prevent crash in ctypes.CField when `byte_size` is incorrect (#132475) Fix: Prevent crash in ctypes.CField when byte_size does not match type size (gh-132470) When creating a ctypes.CField with an incorrect byte_size (e.g., using `byte_size=2` for `ctypes.c_byte`), the code would previously abort due to the failed assertion `byte_size == info->size`. This commit replaces the assertion with a proper error handling mechanism that raises a `ValueError` when `byte_size` does not match the expected type size. This prevents the crash and provides a more informative error message to the us Co-authored-by: sobolevn --- Lib/test/test_ctypes/test_struct_fields.py | 13 ++++++++++++- .../2025-04-13-20-52-39.gh-issue-132470.UqBQjN.rst | 2 ++ Modules/_ctypes/cfield.c | 7 ++++++- 3 files changed, 20 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/C_API/2025-04-13-20-52-39.gh-issue-132470.UqBQjN.rst diff --git a/Lib/test/test_ctypes/test_struct_fields.py b/Lib/test/test_ctypes/test_struct_fields.py index 5c713247a0f..b50bbcbb65c 100644 --- a/Lib/test/test_ctypes/test_struct_fields.py +++ b/Lib/test/test_ctypes/test_struct_fields.py @@ -1,6 +1,6 @@ import unittest import sys -from ctypes import Structure, Union, sizeof, c_char, c_int, CField +from ctypes import Structure, Union, sizeof, c_byte, c_char, c_int, CField from ._support import Py_TPFLAGS_IMMUTABLETYPE, StructCheckMixin @@ -75,6 +75,17 @@ class FieldsTestBase(StructCheckMixin): 'ctypes state is not initialized'): class Subclass(BrokenStructure): ... + def test_invalid_byte_size_raises_gh132470(self): + with self.assertRaisesRegex(ValueError, r"does not match type size"): + CField( + name="a", + type=c_byte, + byte_size=2, # Wrong size: c_byte is only 1 byte + byte_offset=2, + index=1, + _internal_use=True + ) + def test_max_field_size_gh126937(self): # Classes for big structs should be created successfully. # (But they most likely can't be instantiated.) diff --git a/Misc/NEWS.d/next/C_API/2025-04-13-20-52-39.gh-issue-132470.UqBQjN.rst b/Misc/NEWS.d/next/C_API/2025-04-13-20-52-39.gh-issue-132470.UqBQjN.rst new file mode 100644 index 00000000000..5a03908fb91 --- /dev/null +++ b/Misc/NEWS.d/next/C_API/2025-04-13-20-52-39.gh-issue-132470.UqBQjN.rst @@ -0,0 +1,2 @@ +Creating a :class:`ctypes.CField` with a *byte_size* that does not match the actual +type size now raises a :exc:`ValueError` instead of crashing the interpreter. diff --git a/Modules/_ctypes/cfield.c b/Modules/_ctypes/cfield.c index ec35686f251..6b63a08ed6e 100644 --- a/Modules/_ctypes/cfield.c +++ b/Modules/_ctypes/cfield.c @@ -99,7 +99,12 @@ PyCField_new_impl(PyTypeObject *type, PyObject *name, PyObject *proto, "type of field %R must be a C type", name); goto error; } - assert(byte_size == info->size); + if (byte_size != info->size) { + PyErr_Format(PyExc_ValueError, + "byte size of field %R (%zd) does not match type size (%zd)", + name, byte_size, info->size); + goto error; + } Py_ssize_t bitfield_size = 0; Py_ssize_t bit_offset = 0;