mirror of https://github.com/python/cpython
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:
parent
1fdfce9452
commit
ce9f84a47b
|
@ -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));
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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), \
|
||||||
|
|
|
@ -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));
|
||||||
|
|
|
@ -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"
|
|
@ -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):
|
||||||
|
for layout in "ms", "gcc-sysv":
|
||||||
|
with self.subTest(layout=layout):
|
||||||
return self.get_except(type(Structure), "X", (),
|
return self.get_except(type(Structure), "X", (),
|
||||||
{"_fields_": fields})
|
{"_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()
|
||||||
|
|
|
@ -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):
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
/*************************************************
|
/*************************************************
|
||||||
*
|
*
|
||||||
|
|
|
@ -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",
|
||||||
*palign = info->align;
|
name, size);
|
||||||
|
goto error;
|
||||||
if (bitsize > 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:
|
|
||||||
Py_ssize_t slot_start_bit = round_down(*pbitofs, 8 * info->align);
|
|
||||||
Py_ssize_t slot_end_bit = slot_start_bit + 8 * info->size;
|
|
||||||
// And see if it also contains the bitfield's last bit:
|
|
||||||
Py_ssize_t field_end_bit = *pbitofs + bitsize;
|
|
||||||
if (field_end_bit > slot_end_bit) {
|
|
||||||
// It doesn't: add padding (bump up to the next alignment boundary)
|
|
||||||
*pbitofs = round_up(*pbitofs, 8*info->align);
|
|
||||||
}
|
}
|
||||||
}
|
// assert: no overflow;
|
||||||
assert(*poffset == 0);
|
if ((unsigned long long int) size
|
||||||
|
>= (1ULL << (8*sizeof(Py_ssize_t)-1)) / 8) {
|
||||||
self->offset = round_down(*pbitofs, 8*info->align) / 8;
|
PyErr_Format(PyExc_ValueError,
|
||||||
if(is_bitfield) {
|
"size of field %R is too big: %zd", name, size);
|
||||||
Py_ssize_t effective_bitsof = *pbitofs - 8 * self->offset;
|
goto error;
|
||||||
self->size = BUILD_SIZE(bitsize, effective_bitsof);
|
|
||||||
assert(effective_bitsof <= info->size * 8);
|
|
||||||
} else {
|
|
||||||
self->size = info->size;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
*pbitofs += bitsize;
|
PyTypeObject *tp = type;
|
||||||
*psize = round_up(*pbitofs, 8) / 8;
|
ctypes_state *st = get_module_state_by_class(tp);
|
||||||
|
self = (CFieldObject *)tp->tp_alloc(tp, 0);
|
||||||
return 0;
|
if (!self) {
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
if (PyUnicode_CheckExact(name)) {
|
||||||
|
self->name = Py_NewRef(name);
|
||||||
|
} else {
|
||||||
|
self->name = PyObject_Str(name);
|
||||||
|
if (!self->name) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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]*/
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue