diff --git a/Doc/c-api/hash.rst b/Doc/c-api/hash.rst index 00f8cb887dc7eb..7aff2c1a0c9533 100644 --- a/Doc/c-api/hash.rst +++ b/Doc/c-api/hash.rst @@ -83,7 +83,7 @@ See also the :c:member:`PyTypeObject.tp_hash` member and :ref:`numeric-hash`. .. c:function:: Py_hash_t Py_HashPointer(const void *ptr) Hash a pointer value: process the pointer value as an integer (cast it to - ``uintptr_t`` internally). The pointer is not dereferenced. + :c:expr:`uintptr_t` internally). The pointer is not dereferenced. The function cannot fail: it cannot return ``-1``. diff --git a/Doc/c-api/structures.rst b/Doc/c-api/structures.rst index 987bc167c68d6c..f702f542f226ac 100644 --- a/Doc/c-api/structures.rst +++ b/Doc/c-api/structures.rst @@ -615,6 +615,7 @@ using e.g. :keyword:`del` or :py:func:`delattr`. ================================ ============================= ====================== Macro name C type Python type ================================ ============================= ====================== +.. c:macro:: Py_T_INTEGER(type) *type* (INT) :py:class:`int` .. c:macro:: Py_T_BYTE :c:expr:`char` :py:class:`int` .. c:macro:: Py_T_SHORT :c:expr:`short` :py:class:`int` .. c:macro:: Py_T_INT :c:expr:`int` :py:class:`int` @@ -630,18 +631,21 @@ Macro name C type Python type .. c:macro:: Py_T_DOUBLE :c:expr:`double` :py:class:`float` .. c:macro:: Py_T_BOOL :c:expr:`char` :py:class:`bool` (written as 0 or 1) -.. c:macro:: Py_T_STRING :c:expr:`const char *` (*) :py:class:`str` (RO) -.. c:macro:: Py_T_STRING_INPLACE :c:expr:`const char[]` (*) :py:class:`str` (RO) -.. c:macro:: Py_T_CHAR :c:expr:`char` (0-127) :py:class:`str` (**) +.. c:macro:: Py_T_STRING :c:expr:`const char *` (STR) :py:class:`str` (RO) +.. c:macro:: Py_T_STRING_INPLACE :c:expr:`const char[]` (STR) :py:class:`str` (RO) +.. c:macro:: Py_T_CHAR :c:expr:`char` (0-127) :py:class:`str` (CH) .. c:macro:: Py_T_OBJECT_EX :c:expr:`PyObject *` :py:class:`object` (D) ================================ ============================= ====================== - (*): Zero-terminated, UTF8-encoded C string. + (INT): Macro :c:macro:`Py_T_INTEGER(type) ` represents an arbitrary + C integer type *type*. + + (STR): Zero-terminated, UTF8-encoded C string. With :c:macro:`!Py_T_STRING` the C representation is a pointer; with :c:macro:`!Py_T_STRING_INPLACE` the string is stored directly in the structure. - (**): String of length 1. Only ASCII is accepted. + (CH): String of length 1. Only ASCII is accepted. (RO): Implies :c:macro:`Py_READONLY`. @@ -687,6 +691,10 @@ Macro name C type Python type Always ``None``. Must be used with :c:macro:`Py_READONLY`. +.. versionadded:: next + Added :c:macro:`Py_T_INTEGER()`. + + Defining Getters and Setters ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/Doc/conf.py b/Doc/conf.py index 467961dd5e2bff..17394e9c2e44c3 100644 --- a/Doc/conf.py +++ b/Doc/conf.py @@ -153,7 +153,9 @@ ('c:type', 'int32_t'), ('c:type', 'int64_t'), ('c:type', 'intmax_t'), + ('c:type', 'intptr_t'), ('c:type', 'off_t'), + ('c:type', 'pid_t'), ('c:type', 'ptrdiff_t'), ('c:type', 'siginfo_t'), ('c:type', 'size_t'), diff --git a/Doc/whatsnew/3.14.rst b/Doc/whatsnew/3.14.rst index 0e30500fc9b997..f3ccdd444839ac 100644 --- a/Doc/whatsnew/3.14.rst +++ b/Doc/whatsnew/3.14.rst @@ -1818,6 +1818,10 @@ New features (Contributed by Victor Stinner in :gh:`120389`.) +* Add support for arbitrary C integer types in :c:member:`PyMemberDef.type`. + The macro :c:macro:`Py_T_INTEGER(type) ` represents a C type *type*. + (Contributed by Serhiy Storchaka and Petr Viktorin in :gh:`117031`.) + * Add :c:func:`PyBytes_Join(sep, iterable) ` function, similar to ``sep.join(iterable)`` in Python. (Contributed by Victor Stinner in :gh:`121645`.) diff --git a/Include/descrobject.h b/Include/descrobject.h index fd66d17b497a31..a7c1a702e71d6a 100644 --- a/Include/descrobject.h +++ b/Include/descrobject.h @@ -79,6 +79,8 @@ struct PyMemberDef { #define Py_T_PYSSIZET 19 /* Py_ssize_t */ #define _Py_T_NONE 20 // Deprecated. Value is always None. +#define Py_T_INTEGER(type) ((sizeof(type) << 8) | (_Py_IS_TYPE_SIGNED(type) ? 1 : 2)) + /* Flags */ #define Py_READONLY 1 #define Py_AUDIT_READ 2 // Added in 3.10, harmless no-op before that diff --git a/Lib/test/test_capi/test_structmembers.py b/Lib/test/test_capi/test_structmembers.py index f14ad9a9a5f512..dc1b770b780e24 100644 --- a/Lib/test/test_capi/test_structmembers.py +++ b/Lib/test/test_capi/test_structmembers.py @@ -10,7 +10,9 @@ INT_MAX, INT_MIN, UINT_MAX, LONG_MAX, LONG_MIN, ULONG_MAX, LLONG_MAX, LLONG_MIN, ULLONG_MAX, - PY_SSIZE_T_MAX, PY_SSIZE_T_MIN, + PY_SSIZE_T_MAX, PY_SSIZE_T_MIN, SIZE_MAX, + SIZEOF_INTMAX_T, SIZEOF_INTPTR_T, SIZEOF_PTRDIFF_T, SIZEOF_OFF_T, + SIZEOF_PID_T, SIZEOF_INT, ) @@ -19,6 +21,8 @@ def __init__(self, value): self.value = value def __index__(self): return self.value + def __repr__(self): + return f'Index({self.value!r})' # There are two classes: one using and another using # `Py_`-prefixed API. They should behave the same in Python @@ -60,22 +64,22 @@ def _test_warn(self, name, value, expected=None): if expected is not None: self.assertEqual(getattr(ts, name), expected) - def _test_overflow(self, name, value): + def _test_overflow(self, name, value, error=OverflowError): ts = self.ts - self.assertRaises(OverflowError, setattr, ts, name, value) + self.assertRaises(error, setattr, ts, name, value) def _test_int_range(self, name, minval, maxval, *, hardlimit=None, - indexlimit=None): + indexlimit=None, negvalueerror=OverflowError, wrap=False): if hardlimit is None: hardlimit = (minval, maxval) ts = self.ts self._test_write(name, minval) - self._test_write(name, maxval) + self._test_write(name, maxval, -1 if wrap else maxval) hardminval, hardmaxval = hardlimit - self._test_overflow(name, hardminval-1) + self._test_overflow(name, hardminval-1, error=negvalueerror) self._test_overflow(name, hardmaxval+1) self._test_overflow(name, 2**1000) - self._test_overflow(name, -2**1000) + self._test_overflow(name, -2**1000, error=negvalueerror) if hardminval < minval: self._test_warn(name, hardminval) self._test_warn(name, minval-1, maxval) @@ -88,11 +92,11 @@ def _test_int_range(self, name, minval, maxval, *, hardlimit=None, self.assertRaises(TypeError, setattr, ts, name, Index(maxval)) else: self._test_write(name, Index(minval), minval) - self._test_write(name, Index(maxval), maxval) - self._test_overflow(name, Index(hardminval-1)) + self._test_write(name, Index(maxval), -1 if wrap else maxval) + self._test_overflow(name, Index(hardminval-1), error=negvalueerror) self._test_overflow(name, Index(hardmaxval+1)) self._test_overflow(name, Index(2**1000)) - self._test_overflow(name, Index(-2**1000)) + self._test_overflow(name, Index(-2**1000), error=negvalueerror) if hardminval < minval: self._test_warn(name, Index(hardminval)) self._test_warn(name, Index(minval-1), maxval) @@ -181,6 +185,42 @@ class ReadWriteTests_OldAPI(ReadWriteTests, unittest.TestCase): class ReadWriteTests_NewAPI(ReadWriteTests, unittest.TestCase): cls = _test_structmembersType_NewAPI + def test_size(self): + self._test_int_range('T_SIZE', 0, SIZE_MAX, negvalueerror=ValueError) + + def test_int8(self): + self._test_int_range('T_INT8', -2**7, 2**7-1) + self._test_int_range('T_UINT8', 0, 2**8-1, negvalueerror=ValueError) + self._test_int_range('T_XINT8', -2**7, 2**8-1, wrap=True) + + def test_int16(self): + self._test_int_range('T_INT16', -2**15, 2**15-1) + self._test_int_range('T_UINT16', 0, 2**16-1, negvalueerror=ValueError) + self._test_int_range('T_XINT16', -2**15, 2**16-1, wrap=True) + + def test_int32(self): + self._test_int_range('T_INT32', -2**31, 2**31-1) + self._test_int_range('T_UINT32', 0, 2**32-1, negvalueerror=ValueError) + self._test_int_range('T_XINT32', -2**31, 2**32-1, wrap=True) + + def test_int64(self): + self._test_int_range('T_INT64', -2**63, 2**63-1) + self._test_int_range('T_UINT64', 0, 2**64-1, negvalueerror=ValueError) + self._test_int_range('T_XINT64', -2**63, 2**64-1, wrap=True) + + def test_intptr(self): + bits = 8*SIZEOF_INTPTR_T + self._test_int_range('T_INTPTR', -2**(bits-1), 2**(bits-1)-1) + self._test_int_range('T_UINTPTR', 0, 2**bits-1, negvalueerror=ValueError) + + def test_off(self): + bits = 8*SIZEOF_OFF_T + self._test_int_range('T_OFF', -2**(bits-1), 2**(bits-1)-1) + + def test_pid(self): + bits = 8*SIZEOF_PID_T + self._test_int_range('T_PID', -2**(bits-1), 2**(bits-1)-1) + if __name__ == "__main__": unittest.main() diff --git a/Misc/NEWS.d/next/C_API/2024-03-19-21-13-20.gh-issue-117031.0s3Ruq.rst b/Misc/NEWS.d/next/C_API/2024-03-19-21-13-20.gh-issue-117031.0s3Ruq.rst new file mode 100644 index 00000000000000..624128cf558f8f --- /dev/null +++ b/Misc/NEWS.d/next/C_API/2024-03-19-21-13-20.gh-issue-117031.0s3Ruq.rst @@ -0,0 +1,2 @@ +Add support for arbitrary C integer types in :c:member:`PyMemberDef.type`. +The macro :c:macro:`Py_T_INTEGER(type) ` represents a C type *type*. diff --git a/Modules/_multiprocessing/multiprocessing.h b/Modules/_multiprocessing/multiprocessing.h index 099004b437828e..f304a7bb5c7735 100644 --- a/Modules/_multiprocessing/multiprocessing.h +++ b/Modules/_multiprocessing/multiprocessing.h @@ -60,15 +60,8 @@ * Format codes */ -#if SIZEOF_VOID_P == SIZEOF_LONG -# define F_POINTER "k" -# define T_POINTER T_ULONG -#elif SIZEOF_VOID_P == SIZEOF_LONG_LONG -# define F_POINTER "K" -# define T_POINTER T_ULONGLONG -#else -# error "can't find format code for unsigned integer of same size as void*" -#endif +#define F_POINTER _Py_PARSE_UINTPTR +#define T_POINTER Py_T_INTEGER(uintptr_t) #ifdef MS_WINDOWS # define F_HANDLE F_POINTER diff --git a/Modules/_testcapi/structmember.c b/Modules/_testcapi/structmember.c index ef30a5a9944e3c..dded419cbbd56a 100644 --- a/Modules/_testcapi/structmember.c +++ b/Modules/_testcapi/structmember.c @@ -17,12 +17,33 @@ typedef struct { long long_member; unsigned long ulong_member; Py_ssize_t pyssizet_member; + size_t size_member; float float_member; double double_member; char inplace_member[6]; long long longlong_member; unsigned long long ulonglong_member; char char_member; + int8_t int8_member; + uint8_t uint8_member; + uint8_t xint8_member; + int16_t int16_member; + uint16_t uint16_member; + uint16_t xint16_member; + int32_t int32_member; + uint32_t uint32_member; + uint32_t xint32_member; + int64_t int64_member; + uint64_t uint64_member; + uint64_t xint64_member; + intptr_t intptr_member; + uintptr_t uintptr_member; +#ifdef MS_WINDOWS + long long off_member; +#else + off_t off_member; +#endif + pid_t pid_member; } all_structmembers; typedef struct { @@ -42,12 +63,33 @@ static struct PyMemberDef test_members_newapi[] = { {"T_LONG", Py_T_LONG, offsetof(test_structmembers, structmembers.long_member), 0, NULL}, {"T_ULONG", Py_T_ULONG, offsetof(test_structmembers, structmembers.ulong_member), 0, NULL}, {"T_PYSSIZET", Py_T_PYSSIZET, offsetof(test_structmembers, structmembers.pyssizet_member), 0, NULL}, + {"T_SIZE", Py_T_INTEGER(size_t), offsetof(test_structmembers, structmembers.size_member), 0, NULL}, {"T_FLOAT", Py_T_FLOAT, offsetof(test_structmembers, structmembers.float_member), 0, NULL}, {"T_DOUBLE", Py_T_DOUBLE, offsetof(test_structmembers, structmembers.double_member), 0, NULL}, {"T_STRING_INPLACE", Py_T_STRING_INPLACE, offsetof(test_structmembers, structmembers.inplace_member), 0, NULL}, {"T_LONGLONG", Py_T_LONGLONG, offsetof(test_structmembers, structmembers.longlong_member), 0, NULL}, {"T_ULONGLONG", Py_T_ULONGLONG, offsetof(test_structmembers, structmembers.ulonglong_member), 0, NULL}, {"T_CHAR", Py_T_CHAR, offsetof(test_structmembers, structmembers.char_member), 0, NULL}, + {"T_INT8", Py_T_INTEGER(int8_t), offsetof(test_structmembers, structmembers.int8_member), 0, NULL}, + {"T_UINT8", Py_T_INTEGER(uint8_t), offsetof(test_structmembers, structmembers.uint8_member), 0, NULL}, + {"T_XINT8", Py_T_INTEGER(int8_t)|Py_T_INTEGER(uint8_t), offsetof(test_structmembers, structmembers.xint8_member), 0, NULL}, + {"T_INT16", Py_T_INTEGER(int16_t), offsetof(test_structmembers, structmembers.int16_member), 0, NULL}, + {"T_UINT16", Py_T_INTEGER(uint16_t), offsetof(test_structmembers, structmembers.uint16_member), 0, NULL}, + {"T_XINT16", Py_T_INTEGER(int16_t)|Py_T_INTEGER(uint16_t), offsetof(test_structmembers, structmembers.xint16_member), 0, NULL}, + {"T_INT32", Py_T_INTEGER(int32_t), offsetof(test_structmembers, structmembers.int32_member), 0, NULL}, + {"T_UINT32", Py_T_INTEGER(uint32_t), offsetof(test_structmembers, structmembers.uint32_member), 0, NULL}, + {"T_XINT32", Py_T_INTEGER(int32_t)|Py_T_INTEGER(uint32_t), offsetof(test_structmembers, structmembers.xint32_member), 0, NULL}, + {"T_INT64", Py_T_INTEGER(int64_t), offsetof(test_structmembers, structmembers.int64_member), 0, NULL}, + {"T_UINT64", Py_T_INTEGER(uint64_t), offsetof(test_structmembers, structmembers.uint64_member), 0, NULL}, + {"T_XINT64", Py_T_INTEGER(int64_t)|Py_T_INTEGER(uint64_t), offsetof(test_structmembers, structmembers.xint64_member), 0, NULL}, + {"T_INTPTR", Py_T_INTEGER(intptr_t), offsetof(test_structmembers, structmembers.intptr_member), 0, NULL}, + {"T_UINTPTR", Py_T_INTEGER(uintptr_t), offsetof(test_structmembers, structmembers.uintptr_member), 0, NULL}, +#ifdef MS_WINDOWS + {"T_OFF", Py_T_INTEGER(long long), offsetof(test_structmembers, structmembers.off_member), 0, NULL}, +#else + {"T_OFF", Py_T_INTEGER(off_t), offsetof(test_structmembers, structmembers.off_member), 0, NULL}, +#endif + {"T_PID", Py_T_INTEGER(pid_t), offsetof(test_structmembers, structmembers.pid_member), 0, NULL}, {NULL} }; diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index 3aa6e4c9e43a26..084d9183f82fa9 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -3272,6 +3272,15 @@ PyInit__testcapi(void) PyModule_AddObject(m, "SIZEOF_WCHAR_T", PyLong_FromSsize_t(sizeof(wchar_t))); PyModule_AddObject(m, "SIZEOF_VOID_P", PyLong_FromSsize_t(sizeof(void*))); PyModule_AddObject(m, "SIZEOF_TIME_T", PyLong_FromSsize_t(sizeof(time_t))); + PyModule_AddObject(m, "SIZEOF_INTMAX_T", PyLong_FromSsize_t(sizeof(intmax_t))); + PyModule_AddObject(m, "SIZEOF_INTPTR_T", PyLong_FromSsize_t(sizeof(intptr_t))); + PyModule_AddObject(m, "SIZEOF_PTRDIFF_T", PyLong_FromSsize_t(sizeof(ptrdiff_t))); +#ifdef MS_WINDOWS + PyModule_AddObject(m, "SIZEOF_OFF_T", PyLong_FromSsize_t(sizeof(long long))); +#else + PyModule_AddObject(m, "SIZEOF_OFF_T", PyLong_FromSsize_t(sizeof(off_t))); +#endif + PyModule_AddObject(m, "SIZEOF_INT", PyLong_FromSsize_t(sizeof(int))); PyModule_AddObject(m, "SIZEOF_PID_T", PyLong_FromSsize_t(sizeof(pid_t))); PyModule_AddObject(m, "Py_Version", PyLong_FromUnsignedLong(Py_Version)); Py_INCREF(&PyInstanceMethod_Type); diff --git a/Modules/selectmodule.c b/Modules/selectmodule.c index d701026b50887c..7e95e097f66725 100644 --- a/Modules/selectmodule.c +++ b/Modules/selectmodule.c @@ -1799,48 +1799,21 @@ typedef struct kqueue_queue_Object { #define kqueue_queue_Object_CAST(op) ((kqueue_queue_Object *)(op)) -#if (SIZEOF_UINTPTR_T != SIZEOF_VOID_P) -# error uintptr_t does not match void *! -#elif (SIZEOF_UINTPTR_T == SIZEOF_LONG_LONG) -# define T_UINTPTRT Py_T_ULONGLONG -# define T_INTPTRT Py_T_LONGLONG -# define UINTPTRT_FMT_UNIT "K" -# define INTPTRT_FMT_UNIT "L" -#elif (SIZEOF_UINTPTR_T == SIZEOF_LONG) -# define T_UINTPTRT Py_T_ULONG -# define T_INTPTRT Py_T_LONG -# define UINTPTRT_FMT_UNIT "k" -# define INTPTRT_FMT_UNIT "l" -#elif (SIZEOF_UINTPTR_T == SIZEOF_INT) -# define T_UINTPTRT Py_T_UINT -# define T_INTPTRT Py_T_INT -# define UINTPTRT_FMT_UNIT "I" -# define INTPTRT_FMT_UNIT "i" -#else -# error uintptr_t does not match int, long, or long long! -#endif - #if SIZEOF_LONG_LONG == 8 -# define T_INT64 Py_T_LONGLONG # define INT64_FMT_UNIT "L" #elif SIZEOF_LONG == 8 -# define T_INT64 Py_T_LONG # define INT64_FMT_UNIT "l" #elif SIZEOF_INT == 8 -# define T_INT64 Py_T_INT # define INT64_FMT_UNIT "i" #else # define INT64_FMT_UNIT "_" #endif #if SIZEOF_LONG_LONG == 4 -# define T_UINT32 Py_T_ULONGLONG # define UINT32_FMT_UNIT "K" #elif SIZEOF_LONG == 4 -# define T_UINT32 Py_T_ULONG # define UINT32_FMT_UNIT "k" #elif SIZEOF_INT == 4 -# define T_UINT32 Py_T_UINT # define UINT32_FMT_UNIT "I" #else # define UINT32_FMT_UNIT "_" @@ -1850,11 +1823,11 @@ typedef struct kqueue_queue_Object { * kevent is not standard and its members vary across BSDs. */ #ifdef __NetBSD__ -# define FILTER_TYPE T_UINT32 +# define FILTER_TYPE Py_T_INTEGER(uint32_t) # define FILTER_FMT_UNIT UINT32_FMT_UNIT -# define FLAGS_TYPE T_UINT32 +# define FLAGS_TYPE Py_T_INTEGER(uint32_t) # define FLAGS_FMT_UNIT UINT32_FMT_UNIT -# define FFLAGS_TYPE T_UINT32 +# define FFLAGS_TYPE Py_T_INTEGER(uint32_t) # define FFLAGS_FMT_UNIT UINT32_FMT_UNIT #else # define FILTER_TYPE Py_T_SHORT @@ -1866,11 +1839,11 @@ typedef struct kqueue_queue_Object { #endif #if defined(__NetBSD__) || defined(__OpenBSD__) -# define DATA_TYPE T_INT64 +# define DATA_TYPE Py_T_INTEGER(int64_t) # define DATA_FMT_UNIT INT64_FMT_UNIT #else -# define DATA_TYPE T_INTPTRT -# define DATA_FMT_UNIT INTPTRT_FMT_UNIT +# define DATA_TYPE Py_T_INTEGER(intptr_t) +# define DATA_FMT_UNIT _Py_PARSE_INTPTR #endif /* Unfortunately, we can't store python objects in udata, because @@ -1880,12 +1853,12 @@ typedef struct kqueue_queue_Object { #define KQ_OFF(x) offsetof(kqueue_event_Object, x) static struct PyMemberDef kqueue_event_members[] = { - {"ident", T_UINTPTRT, KQ_OFF(e.ident)}, + {"ident", Py_T_INTEGER(uintptr_t), KQ_OFF(e.ident)}, {"filter", FILTER_TYPE, KQ_OFF(e.filter)}, {"flags", FLAGS_TYPE, KQ_OFF(e.flags)}, - {"fflags", Py_T_UINT, KQ_OFF(e.fflags)}, + {"fflags", Py_T_UINT, KQ_OFF(e.fflags)}, {"data", DATA_TYPE, KQ_OFF(e.data)}, - {"udata", T_UINTPTRT, KQ_OFF(e.udata)}, + {"udata", Py_T_INTEGER(uintptr_t), KQ_OFF(e.udata)}, {NULL} /* Sentinel */ }; #undef KQ_OFF @@ -1909,7 +1882,7 @@ kqueue_event_init(PyObject *op, PyObject *args, PyObject *kwds) "data", "udata", NULL}; static const char fmt[] = "O|" FILTER_FMT_UNIT FLAGS_FMT_UNIT FFLAGS_FMT_UNIT DATA_FMT_UNIT - UINTPTRT_FMT_UNIT ":kevent"; + _Py_PARSE_UINTPTR ":kevent"; kqueue_event_Object *self = kqueue_event_Object_CAST(op); EV_SET(&(self->e), 0, EVFILT_READ, EV_ADD, 0, 0, 0); /* defaults */ diff --git a/Python/structmember.c b/Python/structmember.c index d36e049d6b5d20..dc5cff25a46239 100644 --- a/Python/structmember.c +++ b/Python/structmember.c @@ -7,6 +7,8 @@ #include "pycore_object.h" // _Py_TryIncrefCompare(), FT_ATOMIC_*() #include "pycore_critical_section.h" +#include + static inline PyObject * member_get_object(const char *addr, const char *obj_addr, PyMemberDef *l) @@ -116,6 +118,21 @@ PyMember_GetOne(const char *obj_addr, PyMemberDef *l) v = Py_NewRef(Py_None); break; default: + if (l->type > 0xff && l->type <= 0xffff && (l->type & (0xff & ~0x03)) == 0) { + Py_ssize_t size = l->type >> 8; + if ((l->type & 0x03) == 1) { + v = PyLong_FromNativeBytes(addr, size, -1); + break; + } + else if ((l->type & 0x03) == 2) { + v = PyLong_FromUnsignedNativeBytes(addr, size, -1); + break; + } + else if ((l->type & 0x03) == 3) { + v = PyLong_FromNativeBytes(addr, size, -1); + break; + } + } PyErr_SetString(PyExc_SystemError, "bad memberdescr type"); v = NULL; } @@ -362,6 +379,27 @@ PyMember_SetOne(char *addr, PyMemberDef *l, PyObject *v) break; } default: + if (l->type > 0xff && l->type <= 0xffff && (l->type & (0xff & ~0x03)) == 0) { + Py_ssize_t size = l->type >> 8; + int flags = Py_ASNATIVEBYTES_NATIVE_ENDIAN + | Py_ASNATIVEBYTES_ALLOW_INDEX; + if ((l->type & 0x03) == 2) { + flags |= Py_ASNATIVEBYTES_UNSIGNED_BUFFER + | Py_ASNATIVEBYTES_REJECT_NEGATIVE; + } + else if ((l->type & 0x03) == 3) { + flags |= Py_ASNATIVEBYTES_UNSIGNED_BUFFER; + } + Py_ssize_t bytes = PyLong_AsNativeBytes(v, addr, size, flags); + if (bytes < 0) { + return -1; + } + if (bytes > size) { + PyErr_SetString(PyExc_OverflowError, "int too big to convert"); + return -1; + } + break; + } PyErr_Format(PyExc_SystemError, "bad memberdescr type for %s", l->name); return -1;