gh-97588: Move ctypes struct/union layout logic to Python (GH-123352)

Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com>
This commit is contained in:
Petr Viktorin 2024-09-05 11:20:07 +02:00 committed by GitHub
parent 1fdfce9452
commit ce9f84a47b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 809 additions and 671 deletions

View File

@ -738,7 +738,6 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) {
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_abc_impl)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_abc_impl));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_abstract_)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_abstract_));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_active)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_active));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_align_));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_anonymous_)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_anonymous_));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_argtypes_)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_argtypes_));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_as_parameter_)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_as_parameter_));
@ -759,21 +758,18 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) {
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_initializing)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_initializing));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_io)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_io));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_is_text_encoding)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_is_text_encoding));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_layout_));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_length_)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_length_));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_limbo)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_limbo));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_lock_unlock_module)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_lock_unlock_module));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_loop)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_loop));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_needs_com_addref_)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_needs_com_addref_));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_only_immortal)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_only_immortal));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_pack_));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_restype_)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_restype_));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_showwarnmsg)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_showwarnmsg));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_shutdown)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_shutdown));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_slotnames)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_slotnames));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_strptime)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_strptime));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_strptime_datetime)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_strptime_datetime));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_swappedbytes_));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_type_)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_type_));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_uninitialized_submodules)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_uninitialized_submodules));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_warn_unawaited_coroutine)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_warn_unawaited_coroutine));
@ -787,6 +783,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) {
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(after_in_parent)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(after_in_parent));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(aggregate_class)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(aggregate_class));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(alias)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(alias));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(align));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(allow_code)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(allow_code));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(append)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(append));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(arg)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(arg));
@ -806,6 +803,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) {
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(before)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(before));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(big)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(big));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(binary_form)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(binary_form));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(bit_size));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(block)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(block));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(bound)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(bound));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(buffer)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(buffer));
@ -934,6 +932,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) {
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(fd2)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(fd2));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(fdel)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(fdel));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(fget)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(fget));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(fields));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(file)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(file));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(file_actions)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(file_actions));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(filename)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(filename));
@ -950,6 +949,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) {
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(fold)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(fold));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(follow_symlinks)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(follow_symlinks));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(format)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(format));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(format_spec));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(from_param)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(from_param));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(fromlist)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(fromlist));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(fromtimestamp)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(fromtimestamp));
@ -986,6 +986,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) {
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(importlib)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(importlib));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(in_fd)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(in_fd));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(incoming)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(incoming));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(index));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(indexgroup)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(indexgroup));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(inf)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(inf));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(infer_variance)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(infer_variance));
@ -1006,6 +1007,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) {
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(intersection)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(intersection));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(interval)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(interval));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(is_running)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(is_running));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(is_struct));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(isatty)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(isatty));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(isinstance)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(isinstance));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(isoformat)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(isoformat));

View File

@ -227,7 +227,6 @@ struct _Py_global_strings {
STRUCT_FOR_ID(_abc_impl) STRUCT_FOR_ID(_abc_impl)
STRUCT_FOR_ID(_abstract_) STRUCT_FOR_ID(_abstract_)
STRUCT_FOR_ID(_active) STRUCT_FOR_ID(_active)
STRUCT_FOR_ID(_align_)
STRUCT_FOR_ID(_anonymous_) STRUCT_FOR_ID(_anonymous_)
STRUCT_FOR_ID(_argtypes_) STRUCT_FOR_ID(_argtypes_)
STRUCT_FOR_ID(_as_parameter_) STRUCT_FOR_ID(_as_parameter_)
@ -248,21 +247,18 @@ struct _Py_global_strings {
STRUCT_FOR_ID(_initializing) STRUCT_FOR_ID(_initializing)
STRUCT_FOR_ID(_io) STRUCT_FOR_ID(_io)
STRUCT_FOR_ID(_is_text_encoding) STRUCT_FOR_ID(_is_text_encoding)
STRUCT_FOR_ID(_layout_)
STRUCT_FOR_ID(_length_) STRUCT_FOR_ID(_length_)
STRUCT_FOR_ID(_limbo) STRUCT_FOR_ID(_limbo)
STRUCT_FOR_ID(_lock_unlock_module) STRUCT_FOR_ID(_lock_unlock_module)
STRUCT_FOR_ID(_loop) STRUCT_FOR_ID(_loop)
STRUCT_FOR_ID(_needs_com_addref_) STRUCT_FOR_ID(_needs_com_addref_)
STRUCT_FOR_ID(_only_immortal) STRUCT_FOR_ID(_only_immortal)
STRUCT_FOR_ID(_pack_)
STRUCT_FOR_ID(_restype_) STRUCT_FOR_ID(_restype_)
STRUCT_FOR_ID(_showwarnmsg) STRUCT_FOR_ID(_showwarnmsg)
STRUCT_FOR_ID(_shutdown) STRUCT_FOR_ID(_shutdown)
STRUCT_FOR_ID(_slotnames) STRUCT_FOR_ID(_slotnames)
STRUCT_FOR_ID(_strptime) STRUCT_FOR_ID(_strptime)
STRUCT_FOR_ID(_strptime_datetime) STRUCT_FOR_ID(_strptime_datetime)
STRUCT_FOR_ID(_swappedbytes_)
STRUCT_FOR_ID(_type_) STRUCT_FOR_ID(_type_)
STRUCT_FOR_ID(_uninitialized_submodules) STRUCT_FOR_ID(_uninitialized_submodules)
STRUCT_FOR_ID(_warn_unawaited_coroutine) STRUCT_FOR_ID(_warn_unawaited_coroutine)
@ -276,6 +272,7 @@ struct _Py_global_strings {
STRUCT_FOR_ID(after_in_parent) STRUCT_FOR_ID(after_in_parent)
STRUCT_FOR_ID(aggregate_class) STRUCT_FOR_ID(aggregate_class)
STRUCT_FOR_ID(alias) STRUCT_FOR_ID(alias)
STRUCT_FOR_ID(align)
STRUCT_FOR_ID(allow_code) STRUCT_FOR_ID(allow_code)
STRUCT_FOR_ID(append) STRUCT_FOR_ID(append)
STRUCT_FOR_ID(arg) STRUCT_FOR_ID(arg)
@ -295,6 +292,7 @@ struct _Py_global_strings {
STRUCT_FOR_ID(before) STRUCT_FOR_ID(before)
STRUCT_FOR_ID(big) STRUCT_FOR_ID(big)
STRUCT_FOR_ID(binary_form) STRUCT_FOR_ID(binary_form)
STRUCT_FOR_ID(bit_size)
STRUCT_FOR_ID(block) STRUCT_FOR_ID(block)
STRUCT_FOR_ID(bound) STRUCT_FOR_ID(bound)
STRUCT_FOR_ID(buffer) STRUCT_FOR_ID(buffer)
@ -423,6 +421,7 @@ struct _Py_global_strings {
STRUCT_FOR_ID(fd2) STRUCT_FOR_ID(fd2)
STRUCT_FOR_ID(fdel) STRUCT_FOR_ID(fdel)
STRUCT_FOR_ID(fget) STRUCT_FOR_ID(fget)
STRUCT_FOR_ID(fields)
STRUCT_FOR_ID(file) STRUCT_FOR_ID(file)
STRUCT_FOR_ID(file_actions) STRUCT_FOR_ID(file_actions)
STRUCT_FOR_ID(filename) STRUCT_FOR_ID(filename)
@ -439,6 +438,7 @@ struct _Py_global_strings {
STRUCT_FOR_ID(fold) STRUCT_FOR_ID(fold)
STRUCT_FOR_ID(follow_symlinks) STRUCT_FOR_ID(follow_symlinks)
STRUCT_FOR_ID(format) STRUCT_FOR_ID(format)
STRUCT_FOR_ID(format_spec)
STRUCT_FOR_ID(from_param) STRUCT_FOR_ID(from_param)
STRUCT_FOR_ID(fromlist) STRUCT_FOR_ID(fromlist)
STRUCT_FOR_ID(fromtimestamp) STRUCT_FOR_ID(fromtimestamp)
@ -475,6 +475,7 @@ struct _Py_global_strings {
STRUCT_FOR_ID(importlib) STRUCT_FOR_ID(importlib)
STRUCT_FOR_ID(in_fd) STRUCT_FOR_ID(in_fd)
STRUCT_FOR_ID(incoming) STRUCT_FOR_ID(incoming)
STRUCT_FOR_ID(index)
STRUCT_FOR_ID(indexgroup) STRUCT_FOR_ID(indexgroup)
STRUCT_FOR_ID(inf) STRUCT_FOR_ID(inf)
STRUCT_FOR_ID(infer_variance) STRUCT_FOR_ID(infer_variance)
@ -495,6 +496,7 @@ struct _Py_global_strings {
STRUCT_FOR_ID(intersection) STRUCT_FOR_ID(intersection)
STRUCT_FOR_ID(interval) STRUCT_FOR_ID(interval)
STRUCT_FOR_ID(is_running) STRUCT_FOR_ID(is_running)
STRUCT_FOR_ID(is_struct)
STRUCT_FOR_ID(isatty) STRUCT_FOR_ID(isatty)
STRUCT_FOR_ID(isinstance) STRUCT_FOR_ID(isinstance)
STRUCT_FOR_ID(isoformat) STRUCT_FOR_ID(isoformat)

View File

@ -736,7 +736,6 @@ extern "C" {
INIT_ID(_abc_impl), \ INIT_ID(_abc_impl), \
INIT_ID(_abstract_), \ INIT_ID(_abstract_), \
INIT_ID(_active), \ INIT_ID(_active), \
INIT_ID(_align_), \
INIT_ID(_anonymous_), \ INIT_ID(_anonymous_), \
INIT_ID(_argtypes_), \ INIT_ID(_argtypes_), \
INIT_ID(_as_parameter_), \ INIT_ID(_as_parameter_), \
@ -757,21 +756,18 @@ extern "C" {
INIT_ID(_initializing), \ INIT_ID(_initializing), \
INIT_ID(_io), \ INIT_ID(_io), \
INIT_ID(_is_text_encoding), \ INIT_ID(_is_text_encoding), \
INIT_ID(_layout_), \
INIT_ID(_length_), \ INIT_ID(_length_), \
INIT_ID(_limbo), \ INIT_ID(_limbo), \
INIT_ID(_lock_unlock_module), \ INIT_ID(_lock_unlock_module), \
INIT_ID(_loop), \ INIT_ID(_loop), \
INIT_ID(_needs_com_addref_), \ INIT_ID(_needs_com_addref_), \
INIT_ID(_only_immortal), \ INIT_ID(_only_immortal), \
INIT_ID(_pack_), \
INIT_ID(_restype_), \ INIT_ID(_restype_), \
INIT_ID(_showwarnmsg), \ INIT_ID(_showwarnmsg), \
INIT_ID(_shutdown), \ INIT_ID(_shutdown), \
INIT_ID(_slotnames), \ INIT_ID(_slotnames), \
INIT_ID(_strptime), \ INIT_ID(_strptime), \
INIT_ID(_strptime_datetime), \ INIT_ID(_strptime_datetime), \
INIT_ID(_swappedbytes_), \
INIT_ID(_type_), \ INIT_ID(_type_), \
INIT_ID(_uninitialized_submodules), \ INIT_ID(_uninitialized_submodules), \
INIT_ID(_warn_unawaited_coroutine), \ INIT_ID(_warn_unawaited_coroutine), \
@ -785,6 +781,7 @@ extern "C" {
INIT_ID(after_in_parent), \ INIT_ID(after_in_parent), \
INIT_ID(aggregate_class), \ INIT_ID(aggregate_class), \
INIT_ID(alias), \ INIT_ID(alias), \
INIT_ID(align), \
INIT_ID(allow_code), \ INIT_ID(allow_code), \
INIT_ID(append), \ INIT_ID(append), \
INIT_ID(arg), \ INIT_ID(arg), \
@ -804,6 +801,7 @@ extern "C" {
INIT_ID(before), \ INIT_ID(before), \
INIT_ID(big), \ INIT_ID(big), \
INIT_ID(binary_form), \ INIT_ID(binary_form), \
INIT_ID(bit_size), \
INIT_ID(block), \ INIT_ID(block), \
INIT_ID(bound), \ INIT_ID(bound), \
INIT_ID(buffer), \ INIT_ID(buffer), \
@ -932,6 +930,7 @@ extern "C" {
INIT_ID(fd2), \ INIT_ID(fd2), \
INIT_ID(fdel), \ INIT_ID(fdel), \
INIT_ID(fget), \ INIT_ID(fget), \
INIT_ID(fields), \
INIT_ID(file), \ INIT_ID(file), \
INIT_ID(file_actions), \ INIT_ID(file_actions), \
INIT_ID(filename), \ INIT_ID(filename), \
@ -948,6 +947,7 @@ extern "C" {
INIT_ID(fold), \ INIT_ID(fold), \
INIT_ID(follow_symlinks), \ INIT_ID(follow_symlinks), \
INIT_ID(format), \ INIT_ID(format), \
INIT_ID(format_spec), \
INIT_ID(from_param), \ INIT_ID(from_param), \
INIT_ID(fromlist), \ INIT_ID(fromlist), \
INIT_ID(fromtimestamp), \ INIT_ID(fromtimestamp), \
@ -984,6 +984,7 @@ extern "C" {
INIT_ID(importlib), \ INIT_ID(importlib), \
INIT_ID(in_fd), \ INIT_ID(in_fd), \
INIT_ID(incoming), \ INIT_ID(incoming), \
INIT_ID(index), \
INIT_ID(indexgroup), \ INIT_ID(indexgroup), \
INIT_ID(inf), \ INIT_ID(inf), \
INIT_ID(infer_variance), \ INIT_ID(infer_variance), \
@ -1004,6 +1005,7 @@ extern "C" {
INIT_ID(intersection), \ INIT_ID(intersection), \
INIT_ID(interval), \ INIT_ID(interval), \
INIT_ID(is_running), \ INIT_ID(is_running), \
INIT_ID(is_struct), \
INIT_ID(isatty), \ INIT_ID(isatty), \
INIT_ID(isinstance), \ INIT_ID(isinstance), \
INIT_ID(isoformat), \ INIT_ID(isoformat), \

View File

@ -708,10 +708,6 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) {
_PyUnicode_InternStatic(interp, &string); _PyUnicode_InternStatic(interp, &string);
assert(_PyUnicode_CheckConsistency(string, 1)); assert(_PyUnicode_CheckConsistency(string, 1));
assert(PyUnicode_GET_LENGTH(string) != 1); assert(PyUnicode_GET_LENGTH(string) != 1);
string = &_Py_ID(_align_);
_PyUnicode_InternStatic(interp, &string);
assert(_PyUnicode_CheckConsistency(string, 1));
assert(PyUnicode_GET_LENGTH(string) != 1);
string = &_Py_ID(_anonymous_); string = &_Py_ID(_anonymous_);
_PyUnicode_InternStatic(interp, &string); _PyUnicode_InternStatic(interp, &string);
assert(_PyUnicode_CheckConsistency(string, 1)); assert(_PyUnicode_CheckConsistency(string, 1));
@ -792,10 +788,6 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) {
_PyUnicode_InternStatic(interp, &string); _PyUnicode_InternStatic(interp, &string);
assert(_PyUnicode_CheckConsistency(string, 1)); assert(_PyUnicode_CheckConsistency(string, 1));
assert(PyUnicode_GET_LENGTH(string) != 1); assert(PyUnicode_GET_LENGTH(string) != 1);
string = &_Py_ID(_layout_);
_PyUnicode_InternStatic(interp, &string);
assert(_PyUnicode_CheckConsistency(string, 1));
assert(PyUnicode_GET_LENGTH(string) != 1);
string = &_Py_ID(_length_); string = &_Py_ID(_length_);
_PyUnicode_InternStatic(interp, &string); _PyUnicode_InternStatic(interp, &string);
assert(_PyUnicode_CheckConsistency(string, 1)); assert(_PyUnicode_CheckConsistency(string, 1));
@ -820,10 +812,6 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) {
_PyUnicode_InternStatic(interp, &string); _PyUnicode_InternStatic(interp, &string);
assert(_PyUnicode_CheckConsistency(string, 1)); assert(_PyUnicode_CheckConsistency(string, 1));
assert(PyUnicode_GET_LENGTH(string) != 1); assert(PyUnicode_GET_LENGTH(string) != 1);
string = &_Py_ID(_pack_);
_PyUnicode_InternStatic(interp, &string);
assert(_PyUnicode_CheckConsistency(string, 1));
assert(PyUnicode_GET_LENGTH(string) != 1);
string = &_Py_ID(_restype_); string = &_Py_ID(_restype_);
_PyUnicode_InternStatic(interp, &string); _PyUnicode_InternStatic(interp, &string);
assert(_PyUnicode_CheckConsistency(string, 1)); assert(_PyUnicode_CheckConsistency(string, 1));
@ -848,10 +836,6 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) {
_PyUnicode_InternStatic(interp, &string); _PyUnicode_InternStatic(interp, &string);
assert(_PyUnicode_CheckConsistency(string, 1)); assert(_PyUnicode_CheckConsistency(string, 1));
assert(PyUnicode_GET_LENGTH(string) != 1); assert(PyUnicode_GET_LENGTH(string) != 1);
string = &_Py_ID(_swappedbytes_);
_PyUnicode_InternStatic(interp, &string);
assert(_PyUnicode_CheckConsistency(string, 1));
assert(PyUnicode_GET_LENGTH(string) != 1);
string = &_Py_ID(_type_); string = &_Py_ID(_type_);
_PyUnicode_InternStatic(interp, &string); _PyUnicode_InternStatic(interp, &string);
assert(_PyUnicode_CheckConsistency(string, 1)); assert(_PyUnicode_CheckConsistency(string, 1));
@ -904,6 +888,10 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) {
_PyUnicode_InternStatic(interp, &string); _PyUnicode_InternStatic(interp, &string);
assert(_PyUnicode_CheckConsistency(string, 1)); assert(_PyUnicode_CheckConsistency(string, 1));
assert(PyUnicode_GET_LENGTH(string) != 1); assert(PyUnicode_GET_LENGTH(string) != 1);
string = &_Py_ID(align);
_PyUnicode_InternStatic(interp, &string);
assert(_PyUnicode_CheckConsistency(string, 1));
assert(PyUnicode_GET_LENGTH(string) != 1);
string = &_Py_ID(allow_code); string = &_Py_ID(allow_code);
_PyUnicode_InternStatic(interp, &string); _PyUnicode_InternStatic(interp, &string);
assert(_PyUnicode_CheckConsistency(string, 1)); assert(_PyUnicode_CheckConsistency(string, 1));
@ -980,6 +968,10 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) {
_PyUnicode_InternStatic(interp, &string); _PyUnicode_InternStatic(interp, &string);
assert(_PyUnicode_CheckConsistency(string, 1)); assert(_PyUnicode_CheckConsistency(string, 1));
assert(PyUnicode_GET_LENGTH(string) != 1); assert(PyUnicode_GET_LENGTH(string) != 1);
string = &_Py_ID(bit_size);
_PyUnicode_InternStatic(interp, &string);
assert(_PyUnicode_CheckConsistency(string, 1));
assert(PyUnicode_GET_LENGTH(string) != 1);
string = &_Py_ID(block); string = &_Py_ID(block);
_PyUnicode_InternStatic(interp, &string); _PyUnicode_InternStatic(interp, &string);
assert(_PyUnicode_CheckConsistency(string, 1)); assert(_PyUnicode_CheckConsistency(string, 1));
@ -1492,6 +1484,10 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) {
_PyUnicode_InternStatic(interp, &string); _PyUnicode_InternStatic(interp, &string);
assert(_PyUnicode_CheckConsistency(string, 1)); assert(_PyUnicode_CheckConsistency(string, 1));
assert(PyUnicode_GET_LENGTH(string) != 1); assert(PyUnicode_GET_LENGTH(string) != 1);
string = &_Py_ID(fields);
_PyUnicode_InternStatic(interp, &string);
assert(_PyUnicode_CheckConsistency(string, 1));
assert(PyUnicode_GET_LENGTH(string) != 1);
string = &_Py_ID(file); string = &_Py_ID(file);
_PyUnicode_InternStatic(interp, &string); _PyUnicode_InternStatic(interp, &string);
assert(_PyUnicode_CheckConsistency(string, 1)); assert(_PyUnicode_CheckConsistency(string, 1));
@ -1556,6 +1552,10 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) {
_PyUnicode_InternStatic(interp, &string); _PyUnicode_InternStatic(interp, &string);
assert(_PyUnicode_CheckConsistency(string, 1)); assert(_PyUnicode_CheckConsistency(string, 1));
assert(PyUnicode_GET_LENGTH(string) != 1); assert(PyUnicode_GET_LENGTH(string) != 1);
string = &_Py_ID(format_spec);
_PyUnicode_InternStatic(interp, &string);
assert(_PyUnicode_CheckConsistency(string, 1));
assert(PyUnicode_GET_LENGTH(string) != 1);
string = &_Py_ID(from_param); string = &_Py_ID(from_param);
_PyUnicode_InternStatic(interp, &string); _PyUnicode_InternStatic(interp, &string);
assert(_PyUnicode_CheckConsistency(string, 1)); assert(_PyUnicode_CheckConsistency(string, 1));
@ -1700,6 +1700,10 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) {
_PyUnicode_InternStatic(interp, &string); _PyUnicode_InternStatic(interp, &string);
assert(_PyUnicode_CheckConsistency(string, 1)); assert(_PyUnicode_CheckConsistency(string, 1));
assert(PyUnicode_GET_LENGTH(string) != 1); assert(PyUnicode_GET_LENGTH(string) != 1);
string = &_Py_ID(index);
_PyUnicode_InternStatic(interp, &string);
assert(_PyUnicode_CheckConsistency(string, 1));
assert(PyUnicode_GET_LENGTH(string) != 1);
string = &_Py_ID(indexgroup); string = &_Py_ID(indexgroup);
_PyUnicode_InternStatic(interp, &string); _PyUnicode_InternStatic(interp, &string);
assert(_PyUnicode_CheckConsistency(string, 1)); assert(_PyUnicode_CheckConsistency(string, 1));
@ -1780,6 +1784,10 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) {
_PyUnicode_InternStatic(interp, &string); _PyUnicode_InternStatic(interp, &string);
assert(_PyUnicode_CheckConsistency(string, 1)); assert(_PyUnicode_CheckConsistency(string, 1));
assert(PyUnicode_GET_LENGTH(string) != 1); assert(PyUnicode_GET_LENGTH(string) != 1);
string = &_Py_ID(is_struct);
_PyUnicode_InternStatic(interp, &string);
assert(_PyUnicode_CheckConsistency(string, 1));
assert(PyUnicode_GET_LENGTH(string) != 1);
string = &_Py_ID(isatty); string = &_Py_ID(isatty);
_PyUnicode_InternStatic(interp, &string); _PyUnicode_InternStatic(interp, &string);
assert(_PyUnicode_CheckConsistency(string, 1)); assert(_PyUnicode_CheckConsistency(string, 1));

337
Lib/ctypes/_layout.py Normal file
View File

@ -0,0 +1,337 @@
"""Python implementation of computing the layout of a struct/union
This code is internal and tightly coupled to the C part. The interface
may change at any time.
"""
import sys
import warnings
import struct
from _ctypes import CField, buffer_info
import ctypes
def round_down(n, multiple):
assert n >= 0
assert multiple > 0
return (n // multiple) * multiple
def round_up(n, multiple):
assert n >= 0
assert multiple > 0
return ((n + multiple - 1) // multiple) * multiple
def LOW_BIT(offset):
return offset & 0xFFFF
def NUM_BITS(bitsize):
return bitsize >> 16
def BUILD_SIZE(bitsize, offset):
assert 0 <= offset, offset
assert offset <= 0xFFFF, offset
# We don't support zero length bitfields.
# And GET_BITFIELD uses NUM_BITS(size) == 0,
# to figure out whether we are handling a bitfield.
assert bitsize > 0, bitsize
result = (bitsize << 16) + offset
assert bitsize == NUM_BITS(result), (bitsize, result)
assert offset == LOW_BIT(result), (offset, result)
return result
def build_size(bit_size, bit_offset, big_endian, type_size):
if big_endian:
return BUILD_SIZE(bit_size, 8 * type_size - bit_offset - bit_size)
return BUILD_SIZE(bit_size, bit_offset)
_INT_MAX = (1 << (ctypes.sizeof(ctypes.c_int) * 8) - 1) - 1
class StructUnionLayout:
def __init__(self, fields, size, align, format_spec):
# sequence of CField objects
self.fields = fields
# total size of the aggregate (rounded up to alignment)
self.size = size
# total alignment requirement of the aggregate
self.align = align
# buffer format specification (as a string, UTF-8 but bes
# kept ASCII-only)
self.format_spec = format_spec
def get_layout(cls, input_fields, is_struct, base):
"""Return a StructUnionLayout for the given class.
Called by PyCStructUnionType_update_stginfo when _fields_ is assigned
to a class.
"""
# Currently there are two modes, selectable using the '_layout_' attribute:
#
# 'gcc-sysv' mode places fields one after another, bit by bit.
# But "each bit field must fit within a single object of its specified
# type" (GCC manual, section 15.8 "Bit Field Packing"). When it doesn't,
# we insert a few bits of padding to avoid that.
#
# 'ms' mode works similar except for bitfield packing. Adjacent
# bit-fields are packed into the same 1-, 2-, or 4-byte allocation unit
# if the integral types are the same size and if the next bit-field fits
# into the current allocation unit without crossing the boundary imposed
# by the common alignment requirements of the bit-fields.
#
# See https://gcc.gnu.org/onlinedocs/gcc/x86-Options.html#index-mms-bitfields
# for details.
# We do not support zero length bitfields (we use bitsize != 0
# elsewhere to indicate a bitfield). Here, non-bitfields have bit_size
# set to size*8.
# For clarity, variables that count bits have `bit` in their names.
layout = getattr(cls, '_layout_', None)
if layout is None:
if sys.platform == 'win32' or getattr(cls, '_pack_', None):
gcc_layout = False
else:
gcc_layout = True
elif layout == 'ms':
gcc_layout = False
elif layout == 'gcc-sysv':
gcc_layout = True
else:
raise ValueError(f'unknown _layout_: {layout!r}')
align = getattr(cls, '_align_', 1)
if align < 0:
raise ValueError('_align_ must be a non-negative integer')
elif align == 0:
# Setting `_align_ = 0` amounts to using the default alignment
align == 1
if base:
align = max(ctypes.alignment(base), align)
swapped_bytes = hasattr(cls, '_swappedbytes_')
if swapped_bytes:
big_endian = sys.byteorder == 'little'
else:
big_endian = sys.byteorder == 'big'
pack = getattr(cls, '_pack_', None)
if pack is not None:
try:
pack = int(pack)
except (TypeError, ValueError):
raise ValueError("_pack_ must be an integer")
if pack < 0:
raise ValueError("_pack_ must be a non-negative integer")
if pack > _INT_MAX:
raise ValueError("_pack_ too big")
if gcc_layout:
raise ValueError('_pack_ is not compatible with gcc-sysv layout')
result_fields = []
if is_struct:
format_spec_parts = ["T{"]
else:
format_spec_parts = ["B"]
last_field_bit_size = 0 # used in MS layout only
# `8 * next_byte_offset + next_bit_offset` points to where the
# next field would start.
next_bit_offset = 0
next_byte_offset = 0
# size if this was a struct (sum of field sizes, plus padding)
struct_size = 0
# max of field sizes; only meaningful for unions
union_size = 0
if base:
struct_size = ctypes.sizeof(base)
if gcc_layout:
next_bit_offset = struct_size * 8
else:
next_byte_offset = struct_size
last_size = struct_size
for i, field in enumerate(input_fields):
if not is_struct:
# Unions start fresh each time
last_field_bit_size = 0
next_bit_offset = 0
next_byte_offset = 0
# Unpack the field
field = tuple(field)
try:
name, ctype = field
except (ValueError, TypeError):
try:
name, ctype, bit_size = field
except (ValueError, TypeError) as exc:
raise ValueError(
'_fields_ must be a sequence of (name, C type) pairs '
+ 'or (name, C type, bit size) triples') from exc
is_bitfield = True
if bit_size <= 0:
raise ValueError(
f'number of bits invalid for bit field {name!r}')
type_size = ctypes.sizeof(ctype)
if bit_size > type_size * 8:
raise ValueError(
f'number of bits invalid for bit field {name!r}')
else:
is_bitfield = False
type_size = ctypes.sizeof(ctype)
bit_size = type_size * 8
type_bit_size = type_size * 8
type_align = ctypes.alignment(ctype) or 1
type_bit_align = type_align * 8
if gcc_layout:
# We don't use next_byte_offset here
assert pack is None
assert next_byte_offset == 0
# Determine whether the bit field, if placed at the next
# free bit, fits within a single object of its specified type.
# That is: determine a "slot", sized & aligned for the
# specified type, which contains the bitfield's beginning:
slot_start_bit = round_down(next_bit_offset, type_bit_align)
slot_end_bit = slot_start_bit + type_bit_size
# And see if it also contains the bitfield's last bit:
field_end_bit = next_bit_offset + bit_size
if field_end_bit > slot_end_bit:
# It doesn't: add padding (bump up to the next
# alignment boundary)
next_bit_offset = round_up(next_bit_offset, type_bit_align)
offset = round_down(next_bit_offset, type_bit_align) // 8
if is_bitfield:
effective_bit_offset = next_bit_offset - 8 * offset
size = build_size(bit_size, effective_bit_offset,
big_endian, type_size)
assert effective_bit_offset <= type_bit_size
else:
assert offset == next_bit_offset / 8
size = type_size
next_bit_offset += bit_size
struct_size = round_up(next_bit_offset, 8) // 8
else:
if pack:
type_align = min(pack, type_align)
# next_byte_offset points to end of current bitfield.
# next_bit_offset is generally non-positive,
# and 8 * next_byte_offset + next_bit_offset points just behind
# the end of the last field we placed.
if (
(0 < next_bit_offset + bit_size)
or (type_bit_size != last_field_bit_size)
):
# Close the previous bitfield (if any)
# and start a new bitfield
next_byte_offset = round_up(next_byte_offset, type_align)
next_byte_offset += type_size
last_field_bit_size = type_bit_size
# Reminder: 8 * (next_byte_offset) + next_bit_offset
# points to where we would start a new field, namely
# just behind where we placed the last field plus an
# allowance for alignment.
next_bit_offset = -last_field_bit_size
assert type_bit_size == last_field_bit_size
offset = next_byte_offset - last_field_bit_size // 8
if is_bitfield:
assert 0 <= (last_field_bit_size + next_bit_offset)
size = build_size(bit_size,
last_field_bit_size + next_bit_offset,
big_endian, type_size)
else:
size = type_size
if type_bit_size:
assert (last_field_bit_size + next_bit_offset) < type_bit_size
next_bit_offset += bit_size
struct_size = next_byte_offset
assert (not is_bitfield) or (LOW_BIT(size) <= size * 8)
# Add the format spec parts
if is_struct:
padding = offset - last_size
format_spec_parts.append(padding_spec(padding))
fieldfmt, bf_ndim, bf_shape = buffer_info(ctype)
if bf_shape:
format_spec_parts.extend((
"(",
','.join(str(n) for n in bf_shape),
")",
))
if fieldfmt is None:
fieldfmt = "B"
if isinstance(name, bytes):
# a bytes name would be rejected later, but we check early
# to avoid a BytesWarning with `python -bb`
raise TypeError(
"field {name!r}: name must be a string, not bytes")
format_spec_parts.append(f"{fieldfmt}:{name}:")
result_fields.append(CField(
name=name,
type=ctype,
size=size,
offset=offset,
bit_size=bit_size if is_bitfield else None,
index=i,
))
if is_bitfield and not gcc_layout:
assert type_bit_size > 0
align = max(align, type_align)
last_size = struct_size
if not is_struct:
union_size = max(struct_size, union_size)
if is_struct:
total_size = struct_size
else:
total_size = union_size
# Adjust the size according to the alignment requirements
aligned_size = round_up(total_size, align)
# Finish up the format spec
if is_struct:
padding = aligned_size - total_size
format_spec_parts.append(padding_spec(padding))
format_spec_parts.append("}")
return StructUnionLayout(
fields=result_fields,
size=aligned_size,
align=align,
format_spec="".join(format_spec_parts),
)
def padding_spec(padding):
if padding <= 0:
return ""
if padding == 1:
return "x"
return f"{padding}x"

View File

@ -5,7 +5,9 @@ from ctypes import (CDLL, Structure, sizeof, POINTER, byref, alignment,
LittleEndianStructure, BigEndianStructure, LittleEndianStructure, BigEndianStructure,
c_byte, c_ubyte, c_char, c_char_p, c_void_p, c_wchar, c_byte, c_ubyte, c_char, c_char_p, c_void_p, c_wchar,
c_uint8, c_uint16, c_uint32, c_uint64, c_uint8, c_uint16, c_uint32, c_uint64,
c_short, c_ushort, c_int, c_uint, c_long, c_ulong, c_longlong, c_ulonglong) c_short, c_ushort, c_int, c_uint, c_long, c_ulong,
c_longlong, c_ulonglong,
Union)
from test import support from test import support
from test.support import import_helper from test.support import import_helper
_ctypes_test = import_helper.import_module("_ctypes_test") _ctypes_test = import_helper.import_module("_ctypes_test")
@ -186,8 +188,10 @@ class BitFieldTest(unittest.TestCase):
self.assertEqual((c_typ, x.a, x.b, x.c), (c_typ, 0, 7, 0)) self.assertEqual((c_typ, x.a, x.b, x.c), (c_typ, 0, 7, 0))
def fail_fields(self, *fields): def fail_fields(self, *fields):
return self.get_except(type(Structure), "X", (), for layout in "ms", "gcc-sysv":
{"_fields_": fields}) with self.subTest(layout=layout):
return self.get_except(type(Structure), "X", (),
{"_fields_": fields, "layout": layout})
def test_nonint_types(self): def test_nonint_types(self):
# bit fields are not allowed on non-integer types. # bit fields are not allowed on non-integer types.
@ -204,9 +208,15 @@ class BitFieldTest(unittest.TestCase):
result = self.fail_fields(("a", c_char, 1)) result = self.fail_fields(("a", c_char, 1))
self.assertEqual(result, (TypeError, 'bit fields not allowed for type c_char')) self.assertEqual(result, (TypeError, 'bit fields not allowed for type c_char'))
class Dummy(Structure): class Empty(Structure):
_fields_ = [] _fields_ = []
result = self.fail_fields(("a", Empty, 1))
self.assertEqual(result, (ValueError, "number of bits invalid for bit field 'a'"))
class Dummy(Structure):
_fields_ = [("x", c_int)]
result = self.fail_fields(("a", Dummy, 1)) result = self.fail_fields(("a", Dummy, 1))
self.assertEqual(result, (TypeError, 'bit fields not allowed for type Dummy')) self.assertEqual(result, (TypeError, 'bit fields not allowed for type Dummy'))
@ -518,6 +528,21 @@ class BitFieldTest(unittest.TestCase):
x.c = 2 x.c = 2
self.assertEqual(b, b'\xab\xcd\xef\x12') self.assertEqual(b, b'\xab\xcd\xef\x12')
def test_union_bitfield(self):
class BitfieldUnion(Union):
_fields_ = [("a", c_uint32, 1),
("b", c_uint32, 2),
("c", c_uint32, 3)]
self.assertEqual(sizeof(BitfieldUnion), 4)
b = bytearray(4)
x = BitfieldUnion.from_buffer(b)
x.a = 1
self.assertEqual(int.from_bytes(b).bit_count(), 1)
x.b = 3
self.assertEqual(int.from_bytes(b).bit_count(), 2)
x.c = 7
self.assertEqual(int.from_bytes(b).bit_count(), 3)
if __name__ == "__main__": if __name__ == "__main__":
unittest.main() unittest.main()

View File

@ -60,7 +60,6 @@ class StructFieldsTestCase(unittest.TestCase):
self.assertRaises(TypeError, CField) self.assertRaises(TypeError, CField)
def test_cfield_type_flags(self): def test_cfield_type_flags(self):
self.assertTrue(CField.__flags__ & Py_TPFLAGS_DISALLOW_INSTANTIATION)
self.assertTrue(CField.__flags__ & Py_TPFLAGS_IMMUTABLETYPE) self.assertTrue(CField.__flags__ & Py_TPFLAGS_IMMUTABLETYPE)
def test_cfield_inheritance_hierarchy(self): def test_cfield_inheritance_hierarchy(self):

View File

@ -320,7 +320,7 @@ _ctypes_alloc_format_string_for_type(char code, int big_endian)
indicator set. If called with a suffix of NULL the error indicator must indicator set. If called with a suffix of NULL the error indicator must
already be set. already be set.
*/ */
char * static char *
_ctypes_alloc_format_string(const char *prefix, const char *suffix) _ctypes_alloc_format_string(const char *prefix, const char *suffix)
{ {
size_t len; size_t len;
@ -352,7 +352,7 @@ _ctypes_alloc_format_string(const char *prefix, const char *suffix)
Returns NULL on failure, with the error indicator set. If called with Returns NULL on failure, with the error indicator set. If called with
a suffix of NULL the error indicator must already be set. a suffix of NULL the error indicator must already be set.
*/ */
char * static char *
_ctypes_alloc_format_string_with_shape(int ndim, const Py_ssize_t *shape, _ctypes_alloc_format_string_with_shape(int ndim, const Py_ssize_t *shape,
const char *prefix, const char *suffix) const char *prefix, const char *suffix)
{ {
@ -664,9 +664,6 @@ StructUnionType_init(PyObject *self, PyObject *args, PyObject *kwds, int isStruc
Py_DECREF(attrdict); Py_DECREF(attrdict);
return -1; return -1;
} }
if (!isStruct) {
info->flags |= TYPEFLAG_HASUNION;
}
info->format = _ctypes_alloc_format_string(NULL, "B"); info->format = _ctypes_alloc_format_string(NULL, "B");
if (info->format == NULL) { if (info->format == NULL) {
@ -2534,6 +2531,10 @@ converters_from_argtypes(ctypes_state *st, PyObject *ob)
return -1; return -1;
} }
// TYPEFLAG_HASUNION and TYPEFLAG_HASBITFIELD used to be set
// if there were any unions/bitfields;
// if the check is re-enabled we either need to loop here or
// restore the flag
if (stginfo != NULL) { if (stginfo != NULL) {
if (stginfo->flags & TYPEFLAG_HASUNION) { if (stginfo->flags & TYPEFLAG_HASUNION) {
Py_DECREF(converters); Py_DECREF(converters);
@ -5780,7 +5781,7 @@ _ctypes_add_types(PyObject *mod)
* Simple classes * Simple classes
*/ */
CREATE_TYPE(st->PyCField_Type, &cfield_spec, NULL, NULL); MOD_ADD_TYPE(st->PyCField_Type, &cfield_spec, NULL, NULL);
/************************************************* /*************************************************
* *

View File

@ -20,6 +20,13 @@
#define CTYPES_CFIELD_CAPSULE_NAME_PYMEM "_ctypes/cfield.c pymem" #define CTYPES_CFIELD_CAPSULE_NAME_PYMEM "_ctypes/cfield.c pymem"
/*[clinic input]
module _ctypes
[clinic start generated code]*/
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=476a19c49b31a75c]*/
#include "clinic/cfield.c.h"
static void pymem_destructor(PyObject *ptr) static void pymem_destructor(PyObject *ptr)
{ {
void *p = PyCapsule_GetPointer(ptr, CTYPES_CFIELD_CAPSULE_NAME_PYMEM); void *p = PyCapsule_GetPointer(ptr, CTYPES_CFIELD_CAPSULE_NAME_PYMEM);
@ -33,6 +40,10 @@ static void pymem_destructor(PyObject *ptr)
/* /*
PyCField_Type PyCField_Type
*/ */
/*[clinic input]
class _ctypes.CField "PyObject *" "PyObject"
[clinic start generated code]*/
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=602817ea3ffc709c]*/
static inline static inline
Py_ssize_t round_down(Py_ssize_t numToRound, Py_ssize_t multiple) Py_ssize_t round_down(Py_ssize_t numToRound, Py_ssize_t multiple)
@ -61,238 +72,142 @@ Py_ssize_t LOW_BIT(Py_ssize_t offset);
static inline static inline
Py_ssize_t BUILD_SIZE(Py_ssize_t bitsize, Py_ssize_t offset); Py_ssize_t BUILD_SIZE(Py_ssize_t bitsize, Py_ssize_t offset);
/* PyCField_FromDesc creates and returns a struct/union field descriptor.
The function expects to be called repeatedly for all fields in a struct or /*[clinic input]
union. It uses helper functions PyCField_FromDesc_gcc and @classmethod
PyCField_FromDesc_msvc to simulate the corresponding compilers. _ctypes.CField.__new__ as PyCField_new
GCC mode places fields one after another, bit by bit. But "each bit field must name: object(subclass_of='&PyUnicode_Type')
fit within a single object of its specified type" (GCC manual, section 15.8 type as proto: object
"Bit Field Packing"). When it doesn't, we insert a few bits of padding to size: Py_ssize_t
avoid that. offset: Py_ssize_t
index: Py_ssize_t
bit_size as bit_size_obj: object = None
MSVC mode works similar except for bitfield packing. Adjacent bit-fields are [clinic start generated code]*/
packed into the same 1-, 2-, or 4-byte allocation unit if the integral types
are the same size and if the next bit-field fits into the current allocation
unit without crossing the boundary imposed by the common alignment requirements
of the bit-fields.
See https://gcc.gnu.org/onlinedocs/gcc/x86-Options.html#index-mms-bitfields for details. static PyObject *
PyCField_new_impl(PyTypeObject *type, PyObject *name, PyObject *proto,
We do not support zero length bitfields. In fact we use bitsize != 0 elsewhere Py_ssize_t size, Py_ssize_t offset, Py_ssize_t index,
to indicate a bitfield. Here, non-bitfields need bitsize set to size*8. PyObject *bit_size_obj)
/*[clinic end generated code: output=43649ef9157c5f58 input=3d813f56373c4caa]*/
PyCField_FromDesc manages:
- *psize: the size of the structure / union so far.
- *poffset, *pbitofs: 8* (*poffset) + *pbitofs points to where the next field
would start.
- *palign: the alignment requirements of the last field we placed.
*/
static int
PyCField_FromDesc_gcc(Py_ssize_t bitsize, Py_ssize_t *pbitofs,
Py_ssize_t *psize, Py_ssize_t *poffset, Py_ssize_t *palign,
CFieldObject* self, StgInfo* info,
int is_bitfield
)
{ {
// We don't use poffset here, so clear it, if it has been set. CFieldObject* self = NULL;
*pbitofs += *poffset * 8; if (size < 0) {
*poffset = 0; PyErr_Format(PyExc_ValueError,
"size of field %R must not be negative, got %zd",
name, size);
goto error;
}
// assert: no overflow;
if ((unsigned long long int) size
>= (1ULL << (8*sizeof(Py_ssize_t)-1)) / 8) {
PyErr_Format(PyExc_ValueError,
"size of field %R is too big: %zd", name, size);
goto error;
}
*palign = info->align; PyTypeObject *tp = type;
ctypes_state *st = get_module_state_by_class(tp);
if (bitsize > 0) { self = (CFieldObject *)tp->tp_alloc(tp, 0);
// Determine whether the bit field, if placed at the next free bit, if (!self) {
// fits within a single object of its specified type. return NULL;
// That is: determine a "slot", sized & aligned for the specified type, }
// which contains the bitfield's beginning: if (PyUnicode_CheckExact(name)) {
Py_ssize_t slot_start_bit = round_down(*pbitofs, 8 * info->align); self->name = Py_NewRef(name);
Py_ssize_t slot_end_bit = slot_start_bit + 8 * info->size; } else {
// And see if it also contains the bitfield's last bit: self->name = PyObject_Str(name);
Py_ssize_t field_end_bit = *pbitofs + bitsize; if (!self->name) {
if (field_end_bit > slot_end_bit) { goto error;
// It doesn't: add padding (bump up to the next alignment boundary)
*pbitofs = round_up(*pbitofs, 8*info->align);
} }
} }
assert(*poffset == 0);
self->offset = round_down(*pbitofs, 8*info->align) / 8;
if(is_bitfield) {
Py_ssize_t effective_bitsof = *pbitofs - 8 * self->offset;
self->size = BUILD_SIZE(bitsize, effective_bitsof);
assert(effective_bitsof <= info->size * 8);
} else {
self->size = info->size;
}
*pbitofs += bitsize;
*psize = round_up(*pbitofs, 8) / 8;
return 0;
}
static int
PyCField_FromDesc_msvc(
Py_ssize_t *pfield_size, Py_ssize_t bitsize,
Py_ssize_t *pbitofs, Py_ssize_t *psize, Py_ssize_t *poffset,
Py_ssize_t *palign, int pack,
CFieldObject* self, StgInfo* info,
int is_bitfield
)
{
if (pack) {
*palign = Py_MIN(pack, info->align);
} else {
*palign = info->align;
}
// *poffset points to end of current bitfield.
// *pbitofs is generally non-positive,
// and 8 * (*poffset) + *pbitofs points just behind
// the end of the last field we placed.
if (0 < *pbitofs + bitsize || 8 * info->size != *pfield_size) {
// Close the previous bitfield (if any).
// and start a new bitfield:
*poffset = round_up(*poffset, *palign);
*poffset += info->size;
*pfield_size = info->size * 8;
// Reminder: 8 * (*poffset) + *pbitofs points to where we would start a
// new field. Ie just behind where we placed the last field plus an
// allowance for alignment.
*pbitofs = - *pfield_size;
}
assert(8 * info->size == *pfield_size);
self->offset = *poffset - (*pfield_size) / 8;
if(is_bitfield) {
assert(0 <= (*pfield_size + *pbitofs));
assert((*pfield_size + *pbitofs) < info->size * 8);
self->size = BUILD_SIZE(bitsize, *pfield_size + *pbitofs);
} else {
self->size = info->size;
}
assert(*pfield_size + *pbitofs <= info->size * 8);
*pbitofs += bitsize;
*psize = *poffset;
return 0;
}
PyObject *
PyCField_FromDesc(ctypes_state *st, PyObject *desc, Py_ssize_t index,
Py_ssize_t *pfield_size, Py_ssize_t bitsize,
Py_ssize_t *pbitofs, Py_ssize_t *psize, Py_ssize_t *poffset, Py_ssize_t *palign,
int pack, int big_endian, LayoutMode layout_mode)
{
PyTypeObject *tp = st->PyCField_Type;
CFieldObject* self = (CFieldObject *)tp->tp_alloc(tp, 0);
if (self == NULL) {
return NULL;
}
StgInfo *info; StgInfo *info;
if (PyStgInfo_FromType(st, desc, &info) < 0) { if (PyStgInfo_FromType(st, proto, &info) < 0) {
Py_DECREF(self); goto error;
return NULL;
} }
if (!info) { if (info == NULL) {
PyErr_SetString(PyExc_TypeError, PyErr_Format(PyExc_TypeError,
"has no _stginfo_"); "type of field %R must be a C type", self->name);
Py_DECREF(self); goto error;
return NULL;
} }
PyObject* proto = desc; Py_ssize_t bit_size = NUM_BITS(size);
if (bit_size) {
assert(bit_size > 0);
assert(bit_size <= info->size * 8);
switch(info->ffi_type_pointer.type) {
case FFI_TYPE_UINT8:
case FFI_TYPE_UINT16:
case FFI_TYPE_UINT32:
case FFI_TYPE_SINT64:
case FFI_TYPE_UINT64:
break;
/* Field descriptors for 'c_char * n' are be scpecial cased to case FFI_TYPE_SINT8:
case FFI_TYPE_SINT16:
case FFI_TYPE_SINT32:
if (info->getfunc != _ctypes_get_fielddesc("c")->getfunc
&& info->getfunc != _ctypes_get_fielddesc("u")->getfunc)
{
break;
}
_Py_FALLTHROUGH; /* else fall through */
default:
PyErr_Format(PyExc_TypeError,
"bit fields not allowed for type %s",
((PyTypeObject*)proto)->tp_name);
goto error;
}
}
self->proto = Py_NewRef(proto);
self->size = size;
self->offset = offset;
self->index = index;
/* Field descriptors for 'c_char * n' are be special cased to
return a Python string instead of an Array object instance... return a Python string instead of an Array object instance...
*/ */
SETFUNC setfunc = NULL; self->setfunc = NULL;
GETFUNC getfunc = NULL; self->getfunc = NULL;
if (PyCArrayTypeObject_Check(st, proto)) { if (PyCArrayTypeObject_Check(st, proto)) {
StgInfo *ainfo; StgInfo *ainfo;
if (PyStgInfo_FromType(st, proto, &ainfo) < 0) { if (PyStgInfo_FromType(st, proto, &ainfo) < 0) {
Py_DECREF(self); goto error;
return NULL;
} }
if (ainfo && ainfo->proto) { if (ainfo && ainfo->proto) {
StgInfo *iinfo; StgInfo *iinfo;
if (PyStgInfo_FromType(st, ainfo->proto, &iinfo) < 0) { if (PyStgInfo_FromType(st, ainfo->proto, &iinfo) < 0) {
Py_DECREF(self); goto error;
return NULL;
} }
if (!iinfo) { if (!iinfo) {
PyErr_SetString(PyExc_TypeError, PyErr_SetString(PyExc_TypeError,
"has no _stginfo_"); "has no _stginfo_");
Py_DECREF(self); goto error;
return NULL;
} }
if (iinfo->getfunc == _ctypes_get_fielddesc("c")->getfunc) { if (iinfo->getfunc == _ctypes_get_fielddesc("c")->getfunc) {
struct fielddesc *fd = _ctypes_get_fielddesc("s"); struct fielddesc *fd = _ctypes_get_fielddesc("s");
getfunc = fd->getfunc; self->getfunc = fd->getfunc;
setfunc = fd->setfunc; self->setfunc = fd->setfunc;
} }
if (iinfo->getfunc == _ctypes_get_fielddesc("u")->getfunc) { if (iinfo->getfunc == _ctypes_get_fielddesc("u")->getfunc) {
struct fielddesc *fd = _ctypes_get_fielddesc("U"); struct fielddesc *fd = _ctypes_get_fielddesc("U");
getfunc = fd->getfunc; self->getfunc = fd->getfunc;
setfunc = fd->setfunc; self->setfunc = fd->setfunc;
} }
} }
} }
self->setfunc = setfunc;
self->getfunc = getfunc;
self->index = index;
self->proto = Py_NewRef(proto);
int is_bitfield = !!bitsize;
if(!is_bitfield) {
assert(info->size >= 0);
// assert: no overflow;
assert((unsigned long long int) info->size
< (1ULL << (8*sizeof(Py_ssize_t)-1)) / 8);
bitsize = 8 * info->size;
// Caution: bitsize might still be 0 now.
}
assert(bitsize <= info->size * 8);
int result;
if (layout_mode == LAYOUT_MODE_MS) {
result = PyCField_FromDesc_msvc(
pfield_size, bitsize, pbitofs,
psize, poffset, palign,
pack,
self, info,
is_bitfield
);
} else {
assert(pack == 0);
result = PyCField_FromDesc_gcc(
bitsize, pbitofs,
psize, poffset, palign,
self, info,
is_bitfield
);
}
if (result < 0) {
Py_DECREF(self);
return NULL;
}
assert(!is_bitfield || (LOW_BIT(self->size) <= self->size * 8));
if(big_endian && is_bitfield) {
self->size = BUILD_SIZE(NUM_BITS(self->size), 8*info->size - LOW_BIT(self->size) - bitsize);
}
return (PyObject *)self; return (PyObject *)self;
error:
Py_XDECREF(self);
return NULL;
} }
static int static int
PyCField_set(CFieldObject *self, PyObject *inst, PyObject *value) PyCField_set(CFieldObject *self, PyObject *inst, PyObject *value)
{ {
@ -371,8 +286,10 @@ PyCField_dealloc(PyObject *self)
{ {
PyTypeObject *tp = Py_TYPE(self); PyTypeObject *tp = Py_TYPE(self);
PyObject_GC_UnTrack(self); PyObject_GC_UnTrack(self);
(void)PyCField_clear((CFieldObject *)self); CFieldObject *self_cf = (CFieldObject *)self;
Py_TYPE(self)->tp_free((PyObject *)self); (void)PyCField_clear(self_cf);
Py_CLEAR(self_cf->name);
Py_TYPE(self)->tp_free(self);
Py_DECREF(tp); Py_DECREF(tp);
} }
@ -398,6 +315,7 @@ PyCField_repr(CFieldObject *self)
} }
static PyType_Slot cfield_slots[] = { static PyType_Slot cfield_slots[] = {
{Py_tp_new, PyCField_new},
{Py_tp_dealloc, PyCField_dealloc}, {Py_tp_dealloc, PyCField_dealloc},
{Py_tp_repr, PyCField_repr}, {Py_tp_repr, PyCField_repr},
{Py_tp_doc, (void *)PyDoc_STR("Structure/Union member")}, {Py_tp_doc, (void *)PyDoc_STR("Structure/Union member")},
@ -413,7 +331,7 @@ PyType_Spec cfield_spec = {
.name = "_ctypes.CField", .name = "_ctypes.CField",
.basicsize = sizeof(CFieldObject), .basicsize = sizeof(CFieldObject),
.flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
Py_TPFLAGS_IMMUTABLETYPE | Py_TPFLAGS_DISALLOW_INSTANTIATION), Py_TPFLAGS_IMMUTABLETYPE),
.slots = cfield_slots, .slots = cfield_slots,
}; };

113
Modules/_ctypes/clinic/cfield.c.h generated Normal file
View File

@ -0,0 +1,113 @@
/*[clinic input]
preserve
[clinic start generated code]*/
#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
# include "pycore_gc.h" // PyGC_Head
# include "pycore_runtime.h" // _Py_ID()
#endif
#include "pycore_abstract.h" // _PyNumber_Index()
#include "pycore_modsupport.h" // _PyArg_UnpackKeywords()
static PyObject *
PyCField_new_impl(PyTypeObject *type, PyObject *name, PyObject *proto,
Py_ssize_t size, Py_ssize_t offset, Py_ssize_t index,
PyObject *bit_size_obj);
static PyObject *
PyCField_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
{
PyObject *return_value = NULL;
#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
#define NUM_KEYWORDS 6
static struct {
PyGC_Head _this_is_not_used;
PyObject_VAR_HEAD
PyObject *ob_item[NUM_KEYWORDS];
} _kwtuple = {
.ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS)
.ob_item = { &_Py_ID(name), &_Py_ID(type), &_Py_ID(size), &_Py_ID(offset), &_Py_ID(index), &_Py_ID(bit_size), },
};
#undef NUM_KEYWORDS
#define KWTUPLE (&_kwtuple.ob_base.ob_base)
#else // !Py_BUILD_CORE
# define KWTUPLE NULL
#endif // !Py_BUILD_CORE
static const char * const _keywords[] = {"name", "type", "size", "offset", "index", "bit_size", NULL};
static _PyArg_Parser _parser = {
.keywords = _keywords,
.fname = "CField",
.kwtuple = KWTUPLE,
};
#undef KWTUPLE
PyObject *argsbuf[6];
PyObject * const *fastargs;
Py_ssize_t nargs = PyTuple_GET_SIZE(args);
Py_ssize_t noptargs = nargs + (kwargs ? PyDict_GET_SIZE(kwargs) : 0) - 5;
PyObject *name;
PyObject *proto;
Py_ssize_t size;
Py_ssize_t offset;
Py_ssize_t index;
PyObject *bit_size_obj = Py_None;
fastargs = _PyArg_UnpackKeywords(_PyTuple_CAST(args)->ob_item, nargs, kwargs, NULL, &_parser, 5, 6, 0, argsbuf);
if (!fastargs) {
goto exit;
}
if (!PyUnicode_Check(fastargs[0])) {
_PyArg_BadArgument("CField", "argument 'name'", "str", fastargs[0]);
goto exit;
}
name = fastargs[0];
proto = fastargs[1];
{
Py_ssize_t ival = -1;
PyObject *iobj = _PyNumber_Index(fastargs[2]);
if (iobj != NULL) {
ival = PyLong_AsSsize_t(iobj);
Py_DECREF(iobj);
}
if (ival == -1 && PyErr_Occurred()) {
goto exit;
}
size = ival;
}
{
Py_ssize_t ival = -1;
PyObject *iobj = _PyNumber_Index(fastargs[3]);
if (iobj != NULL) {
ival = PyLong_AsSsize_t(iobj);
Py_DECREF(iobj);
}
if (ival == -1 && PyErr_Occurred()) {
goto exit;
}
offset = ival;
}
{
Py_ssize_t ival = -1;
PyObject *iobj = _PyNumber_Index(fastargs[4]);
if (iobj != NULL) {
ival = PyLong_AsSsize_t(iobj);
Py_DECREF(iobj);
}
if (ival == -1 && PyErr_Occurred()) {
goto exit;
}
index = ival;
}
if (!noptargs) {
goto skip_optional_pos;
}
bit_size_obj = fastargs[5];
skip_optional_pos:
return_value = PyCField_new_impl(type, name, proto, size, offset, index, bit_size_obj);
exit:
return return_value;
}
/*[clinic end generated code: output=27c010bae9be7213 input=a9049054013a1b77]*/

View File

@ -216,18 +216,6 @@ extern int PyObject_stginfo(PyObject *self, Py_ssize_t *psize, Py_ssize_t *palig
extern struct fielddesc *_ctypes_get_fielddesc(const char *fmt); extern struct fielddesc *_ctypes_get_fielddesc(const char *fmt);
typedef enum {
LAYOUT_MODE_MS,
LAYOUT_MODE_GCC_SYSV,
} LayoutMode;
extern PyObject *
PyCField_FromDesc(ctypes_state *st, PyObject *desc, Py_ssize_t index,
Py_ssize_t *pfield_size, Py_ssize_t bitsize,
Py_ssize_t *pbitofs, Py_ssize_t *psize, Py_ssize_t *poffset,
Py_ssize_t *palign,
int pack, int is_big_endian, LayoutMode layout_mode);
extern PyObject *PyCData_AtAddress(ctypes_state *st, PyObject *type, void *buf); extern PyObject *PyCData_AtAddress(ctypes_state *st, PyObject *type, void *buf);
extern PyObject *PyCData_FromBytes(ctypes_state *st, PyObject *type, char *data, Py_ssize_t length); extern PyObject *PyCData_FromBytes(ctypes_state *st, PyObject *type, char *data, Py_ssize_t length);
@ -259,16 +247,18 @@ struct fielddesc {
GETFUNC getfunc_swapped; GETFUNC getfunc_swapped;
}; };
typedef struct { typedef struct CFieldObject {
PyObject_HEAD PyObject_HEAD
Py_ssize_t offset; Py_ssize_t offset;
Py_ssize_t size; Py_ssize_t size;
Py_ssize_t index; /* Index into CDataObject's Py_ssize_t index; /* Index into CDataObject's
object array */ object array */
PyObject *proto; /* a type or NULL */ PyObject *proto; /* underlying ctype; must have StgInfo */
GETFUNC getfunc; /* getter function if proto is NULL */ GETFUNC getfunc; /* getter function if proto is NULL */
SETFUNC setfunc; /* setter function if proto is NULL */ SETFUNC setfunc; /* setter function if proto is NULL */
int anonymous; int anonymous;
PyObject *name; /* exact PyUnicode */
} CFieldObject; } CFieldObject;
/**************************************************************** /****************************************************************
@ -379,8 +369,6 @@ PyObject *_ctypes_callproc(ctypes_state *st,
#define TYPEFLAG_ISPOINTER 0x100 #define TYPEFLAG_ISPOINTER 0x100
#define TYPEFLAG_HASPOINTER 0x200 #define TYPEFLAG_HASPOINTER 0x200
#define TYPEFLAG_HASUNION 0x400
#define TYPEFLAG_HASBITFIELD 0x800
#define DICTFLAG_FINAL 0x1000 #define DICTFLAG_FINAL 0x1000
@ -436,10 +424,6 @@ extern void *_ctypes_alloc_closure(void);
extern PyObject *PyCData_FromBaseObj(ctypes_state *st, PyObject *type, extern PyObject *PyCData_FromBaseObj(ctypes_state *st, PyObject *type,
PyObject *base, Py_ssize_t index, char *adr); PyObject *base, Py_ssize_t index, char *adr);
extern char *_ctypes_alloc_format_string(const char *prefix, const char *suffix);
extern char *_ctypes_alloc_format_string_with_shape(int ndim,
const Py_ssize_t *shape,
const char *prefix, const char *suffix);
extern int _ctypes_simple_instance(ctypes_state *st, PyObject *obj); extern int _ctypes_simple_instance(ctypes_state *st, PyObject *obj);

View File

@ -210,29 +210,6 @@ MakeAnonFields(PyObject *type)
return 0; return 0;
} }
/*
Allocate a memory block for a pep3118 format string, copy prefix (if
non-null) into it and append `{padding}x` to the end.
Returns NULL on failure, with the error indicator set.
*/
char *
_ctypes_alloc_format_padding(const char *prefix, Py_ssize_t padding)
{
/* int64 decimal characters + x + null */
char buf[19 + 1 + 1];
assert(padding > 0);
if (padding == 1) {
/* Use x instead of 1x, for brevity */
return _ctypes_alloc_format_string(prefix, "x");
}
int ret = PyOS_snprintf(buf, sizeof(buf), "%zdx", padding); (void)ret;
assert(0 <= ret && ret < (Py_ssize_t)sizeof(buf));
return _ctypes_alloc_format_string(prefix, buf);
}
/* /*
Retrieve the (optional) _pack_ attribute from a type, the _fields_ attribute, Retrieve the (optional) _pack_ attribute from a type, the _fields_ attribute,
and initialize StgInfo. Used for Structure and Union subclasses. and initialize StgInfo. Used for Structure and Union subclasses.
@ -240,125 +217,35 @@ _ctypes_alloc_format_padding(const char *prefix, Py_ssize_t padding)
int int
PyCStructUnionType_update_stginfo(PyObject *type, PyObject *fields, int isStruct) PyCStructUnionType_update_stginfo(PyObject *type, PyObject *fields, int isStruct)
{ {
Py_ssize_t len, offset, size, align, i;
Py_ssize_t union_size, total_align, aligned_size;
Py_ssize_t field_size = 0;
Py_ssize_t bitofs = 0;
PyObject *tmp; PyObject *tmp;
int pack;
int forced_alignment = 1;
Py_ssize_t ffi_ofs; Py_ssize_t ffi_ofs;
int big_endian;
int arrays_seen = 0; int arrays_seen = 0;
if (fields == NULL) int retval = -1;
// The following are NULL or hold strong references.
// They're cleared on error.
PyObject *layout_fields = NULL;
PyObject *layout = NULL;
PyObject *format_spec_obj = NULL;
if (fields == NULL) {
return 0; return 0;
int rc = PyObject_HasAttrWithError(type, &_Py_ID(_swappedbytes_));
if (rc < 0) {
return -1;
}
if (rc) {
big_endian = !PY_BIG_ENDIAN;
}
else {
big_endian = PY_BIG_ENDIAN;
}
if (PyObject_GetOptionalAttr(type, &_Py_ID(_pack_), &tmp) < 0) {
return -1;
}
if (tmp) {
pack = PyLong_AsInt(tmp);
Py_DECREF(tmp);
if (pack < 0) {
if (!PyErr_Occurred() ||
PyErr_ExceptionMatches(PyExc_TypeError) ||
PyErr_ExceptionMatches(PyExc_OverflowError))
{
PyErr_SetString(PyExc_ValueError,
"_pack_ must be a non-negative integer");
}
return -1;
}
}
else {
/* Setting `_pack_ = 0` amounts to using the default alignment */
pack = 0;
}
#ifdef MS_WIN32
LayoutMode layout_mode = LAYOUT_MODE_MS;
#else
LayoutMode layout_mode = (pack > 0) ? LAYOUT_MODE_MS : LAYOUT_MODE_GCC_SYSV;
#endif
if (PyObject_GetOptionalAttr(type, &_Py_ID(_layout_), &tmp) < 0) {
return -1;
}
if (tmp) {
if (!PyUnicode_Check(tmp)) {
PyErr_SetString(PyExc_TypeError,
"_layout_ must be a string");
return -1;
}
if (PyUnicode_CompareWithASCIIString(tmp, "ms") == 0) {
layout_mode = LAYOUT_MODE_MS;
}
else if (PyUnicode_CompareWithASCIIString(tmp, "gcc-sysv") == 0) {
layout_mode = LAYOUT_MODE_GCC_SYSV;
if (pack > 0) {
PyErr_SetString(PyExc_ValueError,
"_pack_ is not compatible with _layout_=\"gcc-sysv\"");
return -1;
}
}
else {
PyErr_Format(PyExc_ValueError,
"unknown _layout_ %R", tmp);
return -1;
}
}
if (PyObject_GetOptionalAttr(type, &_Py_ID(_align_), &tmp) < 0) {
return -1;
}
if (tmp) {
forced_alignment = PyLong_AsInt(tmp);
Py_DECREF(tmp);
if (forced_alignment < 0) {
if (!PyErr_Occurred() ||
PyErr_ExceptionMatches(PyExc_TypeError) ||
PyErr_ExceptionMatches(PyExc_OverflowError))
{
PyErr_SetString(PyExc_ValueError,
"_align_ must be a non-negative integer");
}
return -1;
}
}
else {
/* Setting `_align_ = 0` amounts to using the default alignment */
forced_alignment = 1;
}
len = PySequence_Size(fields);
if (len == -1) {
if (PyErr_ExceptionMatches(PyExc_TypeError)) {
PyErr_SetString(PyExc_TypeError,
"'_fields_' must be a sequence of pairs");
}
return -1;
} }
ctypes_state *st = get_module_state_by_def(Py_TYPE(type)); ctypes_state *st = get_module_state_by_def(Py_TYPE(type));
StgInfo *stginfo; StgInfo *stginfo;
if (PyStgInfo_FromType(st, type, &stginfo) < 0) { if (PyStgInfo_FromType(st, type, &stginfo) < 0) {
return -1; goto error;
} }
if (!stginfo) { if (!stginfo) {
PyErr_SetString(PyExc_TypeError, PyErr_SetString(PyExc_TypeError,
"ctypes state is not initialized"); "ctypes state is not initialized");
return -1; goto error;
}
PyObject *base = (PyObject *)((PyTypeObject *)type)->tp_base;
StgInfo *baseinfo;
if (PyStgInfo_FromType(st, base, &baseinfo) < 0) {
goto error;
} }
/* If this structure/union is already marked final we cannot assign /* If this structure/union is already marked final we cannot assign
@ -367,40 +254,114 @@ PyCStructUnionType_update_stginfo(PyObject *type, PyObject *fields, int isStruct
if (stginfo->flags & DICTFLAG_FINAL) {/* is final ? */ if (stginfo->flags & DICTFLAG_FINAL) {/* is final ? */
PyErr_SetString(PyExc_AttributeError, PyErr_SetString(PyExc_AttributeError,
"_fields_ is final"); "_fields_ is final");
return -1; goto error;
}
PyObject *layout_func = _PyImport_GetModuleAttrString("ctypes._layout",
"get_layout");
if (!layout_func) {
goto error;
}
PyObject *kwnames = PyTuple_Pack(
2,
&_Py_ID(is_struct),
&_Py_ID(base));
if (!kwnames) {
goto error;
}
layout = PyObject_Vectorcall(
layout_func,
1 + (PyObject*[]){
NULL,
/* positional args */
type,
fields,
/* keyword args */
isStruct ? Py_True : Py_False,
baseinfo ? base : Py_None},
2 | PY_VECTORCALL_ARGUMENTS_OFFSET,
kwnames);
Py_DECREF(kwnames);
Py_DECREF(layout_func);
fields = NULL; // a borrowed reference we won't be using again
if (!layout) {
goto error;
}
tmp = PyObject_GetAttr(layout, &_Py_ID(align));
if (!tmp) {
goto error;
}
Py_ssize_t total_align = PyLong_AsInt(tmp);
Py_DECREF(tmp);
if (total_align < 0) {
if (!PyErr_Occurred()) {
PyErr_SetString(PyExc_ValueError,
"align must be a non-negative integer");
}
goto error;
}
tmp = PyObject_GetAttr(layout, &_Py_ID(size));
if (!tmp) {
goto error;
}
Py_ssize_t total_size = PyLong_AsInt(tmp);
Py_DECREF(tmp);
if (total_size < 0) {
if (!PyErr_Occurred()) {
PyErr_SetString(PyExc_ValueError,
"size must be a non-negative integer");
}
goto error;
}
format_spec_obj = PyObject_GetAttr(layout, &_Py_ID(format_spec));
if (!format_spec_obj) {
goto error;
}
Py_ssize_t format_spec_size;
const char *format_spec = PyUnicode_AsUTF8AndSize(format_spec_obj,
&format_spec_size);
if (!format_spec) {
goto error;
} }
if (stginfo->format) { if (stginfo->format) {
PyMem_Free(stginfo->format); PyMem_Free(stginfo->format);
stginfo->format = NULL; stginfo->format = NULL;
} }
stginfo->format = PyMem_Malloc(format_spec_size + 1);
if (!stginfo->format) {
PyErr_NoMemory();
goto error;
}
memcpy(stginfo->format, format_spec, format_spec_size + 1);
if (stginfo->ffi_type_pointer.elements) PyObject *layout_fields_obj = PyObject_GetAttr(layout, &_Py_ID(fields));
if (!layout_fields_obj) {
goto error;
}
layout_fields = PySequence_Tuple(layout_fields_obj);
Py_DECREF(layout_fields_obj);
if (!layout_fields) {
goto error;
}
Py_CLEAR(layout);
Py_ssize_t len = PyTuple_GET_SIZE(layout_fields);
if (stginfo->ffi_type_pointer.elements) {
PyMem_Free(stginfo->ffi_type_pointer.elements); PyMem_Free(stginfo->ffi_type_pointer.elements);
stginfo->ffi_type_pointer.elements = NULL;
}
StgInfo *baseinfo;
if (PyStgInfo_FromType(st, (PyObject *)((PyTypeObject *)type)->tp_base,
&baseinfo) < 0) {
return -1;
}
if (baseinfo) { if (baseinfo) {
stginfo->flags |= (baseinfo->flags &
(TYPEFLAG_HASUNION | TYPEFLAG_HASBITFIELD));
}
if (!isStruct) {
stginfo->flags |= TYPEFLAG_HASUNION;
}
if (baseinfo) {
size = offset = baseinfo->size;
align = baseinfo->align;
union_size = 0;
total_align = align ? align : 1;
total_align = max(total_align, forced_alignment);
stginfo->ffi_type_pointer.type = FFI_TYPE_STRUCT; stginfo->ffi_type_pointer.type = FFI_TYPE_STRUCT;
stginfo->ffi_type_pointer.elements = PyMem_New(ffi_type *, baseinfo->length + len + 1); stginfo->ffi_type_pointer.elements = PyMem_New(ffi_type *, baseinfo->length + len + 1);
if (stginfo->ffi_type_pointer.elements == NULL) { if (stginfo->ffi_type_pointer.elements == NULL) {
PyErr_NoMemory(); PyErr_NoMemory();
return -1; goto error;
} }
memset(stginfo->ffi_type_pointer.elements, 0, memset(stginfo->ffi_type_pointer.elements, 0,
sizeof(ffi_type *) * (baseinfo->length + len + 1)); sizeof(ffi_type *) * (baseinfo->length + len + 1));
@ -411,231 +372,61 @@ PyCStructUnionType_update_stginfo(PyObject *type, PyObject *fields, int isStruct
} }
ffi_ofs = baseinfo->length; ffi_ofs = baseinfo->length;
} else { } else {
offset = 0;
size = 0;
align = 0;
union_size = 0;
total_align = forced_alignment;
stginfo->ffi_type_pointer.type = FFI_TYPE_STRUCT; stginfo->ffi_type_pointer.type = FFI_TYPE_STRUCT;
stginfo->ffi_type_pointer.elements = PyMem_New(ffi_type *, len + 1); stginfo->ffi_type_pointer.elements = PyMem_New(ffi_type *, len + 1);
if (stginfo->ffi_type_pointer.elements == NULL) { if (stginfo->ffi_type_pointer.elements == NULL) {
PyErr_NoMemory(); PyErr_NoMemory();
return -1; goto error;
} }
memset(stginfo->ffi_type_pointer.elements, 0, memset(stginfo->ffi_type_pointer.elements, 0,
sizeof(ffi_type *) * (len + 1)); sizeof(ffi_type *) * (len + 1));
ffi_ofs = 0; ffi_ofs = 0;
} }
assert(stginfo->format == NULL); for (Py_ssize_t i = 0; i < len; ++i) {
if (isStruct) { PyObject *prop_obj = PyTuple_GET_ITEM(layout_fields, i);
stginfo->format = _ctypes_alloc_format_string(NULL, "T{"); assert(prop_obj);
} else { if (!PyType_IsSubtype(Py_TYPE(prop_obj), st->PyCField_Type)) {
/* PEP3118 doesn't support union. Use 'B' for bytes. */ PyErr_Format(PyExc_TypeError,
stginfo->format = _ctypes_alloc_format_string(NULL, "B"); "fields must be of type CField, got %T", prop_obj);
} goto error;
if (stginfo->format == NULL)
return -1;
for (i = 0; i < len; ++i) {
PyObject *name = NULL, *desc = NULL;
PyObject *pair = PySequence_GetItem(fields, i);
PyObject *prop;
Py_ssize_t bitsize = 0;
if (!pair || !PyArg_ParseTuple(pair, "UO|n", &name, &desc, &bitsize)) {
PyErr_SetString(PyExc_TypeError,
"'_fields_' must be a sequence of (name, C type) pairs");
Py_XDECREF(pair);
return -1;
} }
if (PyCArrayTypeObject_Check(st, desc)) { CFieldObject *prop = (CFieldObject *)prop_obj; // borrow from prop_obj
if (prop->index != i) {
PyErr_Format(PyExc_ValueError,
"field %R index mismatch (expected %zd, got %zd)",
prop->name, i, prop->index);
goto error;
}
if (PyCArrayTypeObject_Check(st, prop->proto)) {
arrays_seen = 1; arrays_seen = 1;
} }
StgInfo *info; StgInfo *info;
if (PyStgInfo_FromType(st, desc, &info) < 0) { if (PyStgInfo_FromType(st, prop->proto, &info) < 0) {
Py_DECREF(pair); goto error;
return -1;
}
if (info == NULL) {
Py_DECREF(pair);
PyErr_Format(PyExc_TypeError,
"second item in _fields_ tuple (index %zd) must be a C type",
i);
return -1;
} }
assert(info);
stginfo->ffi_type_pointer.elements[ffi_ofs + i] = &info->ffi_type_pointer; stginfo->ffi_type_pointer.elements[ffi_ofs + i] = &info->ffi_type_pointer;
if (info->flags & (TYPEFLAG_ISPOINTER | TYPEFLAG_HASPOINTER)) if (info->flags & (TYPEFLAG_ISPOINTER | TYPEFLAG_HASPOINTER))
stginfo->flags |= TYPEFLAG_HASPOINTER; stginfo->flags |= TYPEFLAG_HASPOINTER;
stginfo->flags |= info->flags & (TYPEFLAG_HASUNION | TYPEFLAG_HASBITFIELD);
info->flags |= DICTFLAG_FINAL; /* mark field type final */ info->flags |= DICTFLAG_FINAL; /* mark field type final */
if (PyTuple_Size(pair) == 3) { /* bits specified */
stginfo->flags |= TYPEFLAG_HASBITFIELD;
switch(info->ffi_type_pointer.type) {
case FFI_TYPE_UINT8:
case FFI_TYPE_UINT16:
case FFI_TYPE_UINT32:
case FFI_TYPE_SINT64:
case FFI_TYPE_UINT64:
break;
case FFI_TYPE_SINT8: if (-1 == PyObject_SetAttr(type, prop->name, prop_obj)) {
case FFI_TYPE_SINT16: goto error;
case FFI_TYPE_SINT32:
if (info->getfunc != _ctypes_get_fielddesc("c")->getfunc
&& info->getfunc != _ctypes_get_fielddesc("u")->getfunc)
{
break;
}
_Py_FALLTHROUGH; /* else fall through */
default:
PyErr_Format(PyExc_TypeError,
"bit fields not allowed for type %s",
((PyTypeObject *)desc)->tp_name);
Py_DECREF(pair);
return -1;
}
if (bitsize <= 0 || bitsize > info->size * 8) {
PyErr_Format(PyExc_ValueError,
"number of bits invalid for bit field %R",
name);
Py_DECREF(pair);
return -1;
}
} else
bitsize = 0;
if (isStruct) {
const char *fieldfmt = info->format ? info->format : "B";
const char *fieldname = PyUnicode_AsUTF8(name);
char *ptr;
Py_ssize_t len;
char *buf;
Py_ssize_t last_size = size;
Py_ssize_t padding;
if (fieldname == NULL)
{
Py_DECREF(pair);
return -1;
}
/* construct the field now, as `prop->offset` is `offset` with
corrected alignment */
prop = PyCField_FromDesc(st, desc, i,
&field_size, bitsize, &bitofs,
&size, &offset, &align,
pack, big_endian, layout_mode);
if (prop == NULL) {
Py_DECREF(pair);
return -1;
}
/* number of bytes between the end of the last field and the start
of this one */
padding = ((CFieldObject *)prop)->offset - last_size;
if (padding > 0) {
ptr = stginfo->format;
stginfo->format = _ctypes_alloc_format_padding(ptr, padding);
PyMem_Free(ptr);
if (stginfo->format == NULL) {
Py_DECREF(pair);
Py_DECREF(prop);
return -1;
}
}
len = strlen(fieldname) + strlen(fieldfmt);
buf = PyMem_Malloc(len + 2 + 1);
if (buf == NULL) {
Py_DECREF(pair);
Py_DECREF(prop);
PyErr_NoMemory();
return -1;
}
sprintf(buf, "%s:%s:", fieldfmt, fieldname);
ptr = stginfo->format;
if (info->shape != NULL) {
stginfo->format = _ctypes_alloc_format_string_with_shape(
info->ndim, info->shape, stginfo->format, buf);
} else {
stginfo->format = _ctypes_alloc_format_string(stginfo->format, buf);
}
PyMem_Free(ptr);
PyMem_Free(buf);
if (stginfo->format == NULL) {
Py_DECREF(pair);
Py_DECREF(prop);
return -1;
}
} else /* union */ {
field_size = 0;
size = 0;
bitofs = 0;
offset = 0;
align = 0;
prop = PyCField_FromDesc(st, desc, i,
&field_size, bitsize, &bitofs,
&size, &offset, &align,
pack, big_endian, layout_mode);
if (prop == NULL) {
Py_DECREF(pair);
return -1;
}
union_size = max(size, union_size);
} }
total_align = max(align, total_align);
if (-1 == PyObject_SetAttr(type, name, prop)) {
Py_DECREF(prop);
Py_DECREF(pair);
return -1;
}
Py_DECREF(pair);
Py_DECREF(prop);
}
if (!isStruct) {
size = union_size;
}
/* Adjust the size according to the alignment requirements */
aligned_size = ((size + total_align - 1) / total_align) * total_align;
if (isStruct) {
char *ptr;
Py_ssize_t padding;
/* Pad up to the full size of the struct */
padding = aligned_size - size;
if (padding > 0) {
ptr = stginfo->format;
stginfo->format = _ctypes_alloc_format_padding(ptr, padding);
PyMem_Free(ptr);
if (stginfo->format == NULL) {
return -1;
}
}
ptr = stginfo->format;
stginfo->format = _ctypes_alloc_format_string(stginfo->format, "}");
PyMem_Free(ptr);
if (stginfo->format == NULL)
return -1;
} }
stginfo->ffi_type_pointer.alignment = Py_SAFE_DOWNCAST(total_align, stginfo->ffi_type_pointer.alignment = Py_SAFE_DOWNCAST(total_align,
Py_ssize_t, Py_ssize_t,
unsigned short); unsigned short);
stginfo->ffi_type_pointer.size = aligned_size; stginfo->ffi_type_pointer.size = total_size;
stginfo->size = aligned_size; stginfo->size = total_size;
stginfo->align = total_align; stginfo->align = total_align;
stginfo->length = ffi_ofs + len; stginfo->length = ffi_ofs + len;
@ -650,7 +441,7 @@ PyCStructUnionType_update_stginfo(PyObject *type, PyObject *fields, int isStruct
# define MAX_STRUCT_SIZE 16 # define MAX_STRUCT_SIZE 16
#endif #endif
if (arrays_seen && (size <= MAX_STRUCT_SIZE)) { if (arrays_seen && (total_size <= MAX_STRUCT_SIZE)) {
/* /*
* See bpo-22273 and gh-110190. Arrays are normally treated as * See bpo-22273 and gh-110190. Arrays are normally treated as
* pointers, which is fine when an array name is being passed as * pointers, which is fine when an array name is being passed as
@ -725,35 +516,19 @@ PyCStructUnionType_update_stginfo(PyObject *type, PyObject *fields, int isStruct
Py_ssize_t struct_index = 0; /* index into dummy structs */ Py_ssize_t struct_index = 0; /* index into dummy structs */
/* first pass to see how much memory to allocate */ /* first pass to see how much memory to allocate */
for (i = 0; i < len; ++i) { for (Py_ssize_t i = 0; i < len; ++i) {
PyObject *name, *desc; PyObject *prop_obj = PyTuple_GET_ITEM(layout_fields, i); // borrowed
PyObject *pair = PySequence_GetItem(fields, i); assert(prop_obj);
int bitsize = 0; assert(PyType_IsSubtype(Py_TYPE(prop_obj), st->PyCField_Type));
CFieldObject *prop = (CFieldObject *)prop_obj; // borrowed
if (pair == NULL) {
return -1;
}
if (!PyArg_ParseTuple(pair, "UO|i", &name, &desc, &bitsize)) {
PyErr_SetString(PyExc_TypeError,
"'_fields_' must be a sequence of (name, C type) pairs");
Py_DECREF(pair);
return -1;
}
StgInfo *info; StgInfo *info;
if (PyStgInfo_FromType(st, desc, &info) < 0) { if (PyStgInfo_FromType(st, prop->proto, &info) < 0) {
Py_DECREF(pair); goto error;
return -1;
}
if (info == NULL) {
Py_DECREF(pair);
PyErr_Format(PyExc_TypeError,
"second item in _fields_ tuple (index %zd) must be a C type",
i);
return -1;
} }
assert(info);
if (!PyCArrayTypeObject_Check(st, desc)) { if (!PyCArrayTypeObject_Check(st, prop->proto)) {
/* Not an array. Just need an ffi_type pointer. */ /* Not an array. Just need an ffi_type pointer. */
num_ffi_type_pointers++; num_ffi_type_pointers++;
} }
@ -763,15 +538,13 @@ PyCStructUnionType_update_stginfo(PyObject *type, PyObject *fields, int isStruct
StgInfo *einfo; StgInfo *einfo;
if (PyStgInfo_FromType(st, info->proto, &einfo) < 0) { if (PyStgInfo_FromType(st, info->proto, &einfo) < 0) {
Py_DECREF(pair); goto error;
return -1;
} }
if (einfo == NULL) { if (einfo == NULL) {
Py_DECREF(pair);
PyErr_Format(PyExc_TypeError, PyErr_Format(PyExc_TypeError,
"second item in _fields_ tuple (index %zd) must be a C type", "second item in _fields_ tuple (index %zd) must be a C type",
i); i);
return -1; goto error;
} }
/* /*
* We need one extra ffi_type to hold the struct, and one * We need one extra ffi_type to hold the struct, and one
@ -781,7 +554,6 @@ PyCStructUnionType_update_stginfo(PyObject *type, PyObject *fields, int isStruct
num_ffi_types++; num_ffi_types++;
num_ffi_type_pointers += length + 1; num_ffi_type_pointers += length + 1;
} }
Py_DECREF(pair);
} }
/* /*
@ -798,7 +570,7 @@ PyCStructUnionType_update_stginfo(PyObject *type, PyObject *fields, int isStruct
if (type_block == NULL) { if (type_block == NULL) {
PyErr_NoMemory(); PyErr_NoMemory();
return -1; goto error;
} }
/* /*
* the first block takes up ffi_ofs + len + 1 which is the pointers * * the first block takes up ffi_ofs + len + 1 which is the pointers *
@ -822,48 +594,21 @@ PyCStructUnionType_update_stginfo(PyObject *type, PyObject *fields, int isStruct
element_index = ffi_ofs; element_index = ffi_ofs;
/* second pass to actually set the type pointers */ /* second pass to actually set the type pointers */
for (i = 0; i < len; ++i) { for (Py_ssize_t i = 0; i < len; ++i) {
PyObject *name, *desc; PyObject *prop_obj = PyTuple_GET_ITEM(layout_fields, i); // borrowed
PyObject *pair = PySequence_GetItem(fields, i); assert(prop_obj);
int bitsize = 0; assert(PyType_IsSubtype(Py_TYPE(prop_obj), st->PyCField_Type));
CFieldObject *prop = (CFieldObject *)prop_obj; // borrowed
if (pair == NULL) {
PyMem_Free(type_block);
return -1;
}
/* In theory, we made this call in the first pass, so it *shouldn't*
* fail. However, you never know, and the code above might change
* later - keeping the check in here is a tad defensive but it
* will affect program size only slightly and performance hardly at
* all.
*/
if (!PyArg_ParseTuple(pair, "UO|i", &name, &desc, &bitsize)) {
PyErr_SetString(PyExc_TypeError,
"'_fields_' must be a sequence of (name, C type) pairs");
Py_DECREF(pair);
PyMem_Free(type_block);
return -1;
}
StgInfo *info; StgInfo *info;
if (PyStgInfo_FromType(st, desc, &info) < 0) { if (PyStgInfo_FromType(st, prop->proto, &info) < 0) {
Py_DECREF(pair);
PyMem_Free(type_block); PyMem_Free(type_block);
return -1; goto error;
}
/* Possibly this check could be avoided, but see above comment. */
if (info == NULL) {
Py_DECREF(pair);
PyMem_Free(type_block);
PyErr_Format(PyExc_TypeError,
"second item in _fields_ tuple (index %zd) must be a C type",
i);
return -1;
} }
assert(info);
assert(element_index < (ffi_ofs + len)); /* will be used below */ assert(element_index < (ffi_ofs + len)); /* will be used below */
if (!PyCArrayTypeObject_Check(st, desc)) { if (!PyCArrayTypeObject_Check(st, prop->proto)) {
/* Not an array. Just copy over the element ffi_type. */ /* Not an array. Just copy over the element ffi_type. */
element_types[element_index++] = &info->ffi_type_pointer; element_types[element_index++] = &info->ffi_type_pointer;
} }
@ -871,17 +616,15 @@ PyCStructUnionType_update_stginfo(PyObject *type, PyObject *fields, int isStruct
Py_ssize_t length = info->length; Py_ssize_t length = info->length;
StgInfo *einfo; StgInfo *einfo;
if (PyStgInfo_FromType(st, info->proto, &einfo) < 0) { if (PyStgInfo_FromType(st, info->proto, &einfo) < 0) {
Py_DECREF(pair);
PyMem_Free(type_block); PyMem_Free(type_block);
return -1; goto error;
} }
if (einfo == NULL) { if (einfo == NULL) {
Py_DECREF(pair);
PyMem_Free(type_block); PyMem_Free(type_block);
PyErr_Format(PyExc_TypeError, PyErr_Format(PyExc_TypeError,
"second item in _fields_ tuple (index %zd) must be a C type", "second item in _fields_ tuple (index %zd) must be a C type",
i); i);
return -1; goto error;
} }
element_types[element_index++] = &structs[struct_index]; element_types[element_index++] = &structs[struct_index];
structs[struct_index].size = length * einfo->ffi_type_pointer.size; structs[struct_index].size = length * einfo->ffi_type_pointer.size;
@ -898,7 +641,6 @@ PyCStructUnionType_update_stginfo(PyObject *type, PyObject *fields, int isStruct
assert(dummy_index < (num_ffi_type_pointers)); assert(dummy_index < (num_ffi_type_pointers));
dummy_types[dummy_index++] = NULL; dummy_types[dummy_index++] = NULL;
} }
Py_DECREF(pair);
} }
element_types[element_index] = NULL; element_types[element_index] = NULL;
@ -916,9 +658,14 @@ PyCStructUnionType_update_stginfo(PyObject *type, PyObject *fields, int isStruct
if (stginfo->flags & DICTFLAG_FINAL) { if (stginfo->flags & DICTFLAG_FINAL) {
PyErr_SetString(PyExc_AttributeError, PyErr_SetString(PyExc_AttributeError,
"Structure or union cannot contain itself"); "Structure or union cannot contain itself");
return -1; goto error;
} }
stginfo->flags |= DICTFLAG_FINAL; stginfo->flags |= DICTFLAG_FINAL;
return MakeAnonFields(type); retval = MakeAnonFields(type);
error:
Py_XDECREF(layout_fields);
Py_XDECREF(layout);
Py_XDECREF(format_spec_obj);
return retval;
} }