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..5b0cf1007f17c9 100644 --- a/Doc/c-api/structures.rst +++ b/Doc/c-api/structures.rst @@ -626,6 +626,22 @@ Macro name C type Python type .. c:macro:: Py_T_ULONG :c:expr:`unsigned long` :py:class:`int` .. c:macro:: Py_T_ULONGLONG :c:expr:`unsigned long long` :py:class:`int` .. c:macro:: Py_T_PYSSIZET :c:expr:`Py_ssize_t` :py:class:`int` +.. c:macro:: Py_T_SSIZE :c:expr:`Py_ssize_t` :py:class:`int` +.. c:macro:: Py_T_SIZE :c:expr:`size_t` :py:class:`int` +.. c:macro:: Py_T_INT8 :c:expr:`int8_t` :py:class:`int` +.. c:macro:: Py_T_UINT8 :c:expr:`uint8_t` :py:class:`int` +.. c:macro:: Py_T_INT16 :c:expr:`int16_t` :py:class:`int` +.. c:macro:: Py_T_UINT16 :c:expr:`uint16_t` :py:class:`int` +.. c:macro:: Py_T_INT32 :c:expr:`int32_t` :py:class:`int` +.. c:macro:: Py_T_UINT32 :c:expr:`uint32_t` :py:class:`int` +.. c:macro:: Py_T_INT64 :c:expr:`int64_t` :py:class:`int` +.. c:macro:: Py_T_UINT64 :c:expr:`uint64_t` :py:class:`int` +.. c:macro:: Py_T_INTPTR :c:expr:`intptr_t` :py:class:`int` +.. c:macro:: Py_T_UINTPTR :c:expr:`uintptr_t` :py:class:`int` +.. c:macro:: Py_T_OFF :c:expr:`off_t` or :py:class:`int` + :c:expr:`long long` + (on Windows) +.. c:macro:: Py_T_PID :c:expr:`pid_t` :py:class:`int` .. c:macro:: Py_T_FLOAT :c:expr:`float` :py:class:`float` .. c:macro:: Py_T_DOUBLE :c:expr:`double` :py:class:`float` .. c:macro:: Py_T_BOOL :c:expr:`char` :py:class:`bool` @@ -687,6 +703,17 @@ Macro name C type Python type Always ``None``. Must be used with :c:macro:`Py_READONLY`. +.. versionadded:: next + + Added :c:macro:`Py_T_SSIZE` (as alias of :c:macro:`Py_T_PYSSIZET`), + :c:macro:`Py_T_SIZE`, :c:macro:`Py_T_INT8`, :c:macro:`Py_T_UINT8`, + :c:macro:`Py_T_INT16`, :c:macro:`Py_T_UINT16`, + :c:macro:`Py_T_INT32`, :c:macro:`Py_T_UINT32`, + :c:macro:`Py_T_INT64`, :c:macro:`Py_T_UINT64`, + :c:macro:`Py_T_INTPTR`, :c:macro:`Py_T_UINTPTR`, + :c:macro:`Py_T_OFF`, and :c:macro:`Py_T_PID`. + + 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..a6b75b7db2f34d 100644 --- a/Doc/whatsnew/3.14.rst +++ b/Doc/whatsnew/3.14.rst @@ -1818,6 +1818,16 @@ New features (Contributed by Victor Stinner in :gh:`120389`.) +* Add support of new member types for :c:member:`PyMemberDef.type`: + :c:macro:`Py_T_SSIZE` (as alias of :c:macro:`Py_T_PYSSIZET`), + :c:macro:`Py_T_SIZE`, :c:macro:`Py_T_INT8`, :c:macro:`Py_T_UINT8`, + :c:macro:`Py_T_INT16`, :c:macro:`Py_T_UINT16`, + :c:macro:`Py_T_INT32`, :c:macro:`Py_T_UINT32`, + :c:macro:`Py_T_INT64`, :c:macro:`Py_T_UINT64`, + :c:macro:`Py_T_INTPTR`, :c:macro:`Py_T_UINTPTR`, + :c:macro:`Py_T_OFF`, and :c:macro:`Py_T_PID`. + (Contributed by Serhiy Storchaka 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..6ad4b412528910 100644 --- a/Include/descrobject.h +++ b/Include/descrobject.h @@ -79,6 +79,26 @@ struct PyMemberDef { #define Py_T_PYSSIZET 19 /* Py_ssize_t */ #define _Py_T_NONE 20 // Deprecated. Value is always None. +#define Py_T_SSIZE Py_T_PYSSIZET +#define Py_T_SIZE 21 +#define Py_T_INTPTR 22 +#define Py_T_UINTPTR 23 +#ifdef MS_WINDOWS +# define Py_T_OFF Py_T_LONGLONG +#else +# define Py_T_OFF 24 +#endif +#define Py_T_PID 25 + +#define Py_T_INT8 0x100|0x1 +#define Py_T_UINT8 0x100|0x2 +#define Py_T_INT16 0x104|0x1 +#define Py_T_UINT16 0x104|0x2 +#define Py_T_INT32 0x108|0x1 +#define Py_T_UINT32 0x108|0x2 +#define Py_T_INT64 0x110|0x1 +#define Py_T_UINT64 0x110|0x2 + /* 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..bf8a1e21b0d8ab 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,43 @@ 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_SSIZE', PY_SSIZE_T_MIN, PY_SSIZE_T_MAX, indexlimit=False) + self._test_int_range('T_SIZE', 0, SIZE_MAX, indexlimit=False) + + 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..9f492de9c55cb2 --- /dev/null +++ b/Misc/NEWS.d/next/C_API/2024-03-19-21-13-20.gh-issue-117031.0s3Ruq.rst @@ -0,0 +1,7 @@ +Add support for new member types for :c:member:`PyMemberDef.type`: +:c:macro:`Py_T_SSIZE` (as alias of :c:macro:`Py_T_PYSSIZET`), +:c:macro:`Py_T_SIZE`, :c:macro:`Py_T_INT8`, :c:macro:`Py_T_UINT8`, +:c:macro:`Py_T_INT16`, :c:macro:`Py_T_UINT16`, :c:macro:`Py_T_INT32`, +:c:macro:`Py_T_UINT32`, :c:macro:`Py_T_INT64`, :c:macro:`Py_T_UINT64`, +:c:macro:`Py_T_INTPTR`, :c:macro:`Py_T_UINTPTR`, :c:macro:`Py_T_OFF`, and +:c:macro:`Py_T_PID`. diff --git a/Modules/_multiprocessing/multiprocessing.h b/Modules/_multiprocessing/multiprocessing.h index 099004b437828e..4bab9046e2ef4e 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_UINTPTR #ifdef MS_WINDOWS # define F_HANDLE F_POINTER diff --git a/Modules/_testcapi/structmember.c b/Modules/_testcapi/structmember.c index ef30a5a9944e3c..fd1daff5f9812c 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,30 @@ 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_SSIZE", Py_T_SSIZE, offsetof(test_structmembers, structmembers.pyssizet_member), 0, NULL}, + {"T_SIZE", Py_T_SIZE, 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_INT8, offsetof(test_structmembers, structmembers.int8_member), 0, NULL}, + {"T_UINT8", Py_T_UINT8, offsetof(test_structmembers, structmembers.uint8_member), 0, NULL}, + {"T_XINT8", Py_T_INT8|Py_T_UINT8, offsetof(test_structmembers, structmembers.xint8_member), 0, NULL}, + {"T_INT16", Py_T_INT16, offsetof(test_structmembers, structmembers.int16_member), 0, NULL}, + {"T_UINT16", Py_T_UINT16, offsetof(test_structmembers, structmembers.uint16_member), 0, NULL}, + {"T_XINT16", Py_T_INT16|Py_T_UINT16, offsetof(test_structmembers, structmembers.xint16_member), 0, NULL}, + {"T_INT32", Py_T_INT32, offsetof(test_structmembers, structmembers.int32_member), 0, NULL}, + {"T_UINT32", Py_T_UINT32, offsetof(test_structmembers, structmembers.uint32_member), 0, NULL}, + {"T_XINT32", Py_T_INT32|Py_T_UINT32, offsetof(test_structmembers, structmembers.xint32_member), 0, NULL}, + {"T_INT64", Py_T_INT64, offsetof(test_structmembers, structmembers.int64_member), 0, NULL}, + {"T_UINT64", Py_T_UINT64, offsetof(test_structmembers, structmembers.uint64_member), 0, NULL}, + {"T_XINT64", Py_T_INT64|Py_T_UINT64, offsetof(test_structmembers, structmembers.xint64_member), 0, NULL}, + {"T_INTPTR", Py_T_INTPTR, offsetof(test_structmembers, structmembers.intptr_member), 0, NULL}, + {"T_UINTPTR", Py_T_UINTPTR, offsetof(test_structmembers, structmembers.uintptr_member), 0, NULL}, + {"T_OFF", Py_T_OFF, offsetof(test_structmembers, structmembers.off_member), 0, NULL}, + {"T_PID", Py_T_PID, 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..bcaf59d8dbb6d8 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_UINT32 # define FILTER_FMT_UNIT UINT32_FMT_UNIT -# define FLAGS_TYPE T_UINT32 +# define FLAGS_TYPE Py_T_UINT32 # define FLAGS_FMT_UNIT UINT32_FMT_UNIT -# define FFLAGS_TYPE T_UINT32 +# define FFLAGS_TYPE Py_T_UINT32 # 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_INT64 # 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_INTPTR +# 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_UINTPTR, 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_UINTPTR, 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..af2fec8edd4a52 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) @@ -63,6 +65,9 @@ PyMember_GetOne(const char *obj_addr, PyMemberDef *l) case Py_T_PYSSIZET: v = PyLong_FromSsize_t(FT_ATOMIC_LOAD_SSIZE_RELAXED(*(Py_ssize_t*)addr)); break; + case Py_T_SIZE: + v = PyLong_FromSize_t(*(size_t*)addr); + break; case Py_T_FLOAT: v = PyFloat_FromDouble((double)FT_ATOMIC_LOAD_FLOAT_RELAXED(*(float*)addr)); break; @@ -115,6 +120,48 @@ PyMember_GetOne(const char *obj_addr, PyMemberDef *l) // doesn't require free-threading code path v = Py_NewRef(Py_None); break; + case Py_T_INT8: + case Py_T_INT8|Py_T_UINT8: + v = PyLong_FromLong(*(int8_t*)addr); + break; + case Py_T_UINT8: + v = PyLong_FromUnsignedLong(*(uint8_t*)addr); + break; + case Py_T_INT16: + case Py_T_INT16|Py_T_UINT16: + v = PyLong_FromLong(*(int16_t*)addr); + break; + case Py_T_UINT16: + v = PyLong_FromUnsignedLong(*(uint16_t*)addr); + break; + case Py_T_INT32: + case Py_T_INT32|Py_T_UINT32: + v = PyLong_FromLong(*(int32_t*)addr); + break; + case Py_T_UINT32: + v = PyLong_FromUnsignedLong(*(uint32_t*)addr); + break; + case Py_T_INT64: + case Py_T_INT64|Py_T_UINT64: + v = PyLong_FromLongLong(*(int64_t*)addr); + break; + case Py_T_UINT64: + v = PyLong_FromUnsignedLongLong(*(uint64_t*)addr); + break; + case Py_T_INTPTR: + v = PyLong_FromNativeBytes(addr, sizeof(intptr_t), -1); + break; + case Py_T_UINTPTR: + v = PyLong_FromUnsignedNativeBytes(addr, sizeof(uintptr_t), -1); + break; +#ifndef MS_WINDOWS + case Py_T_OFF: + v = PyLong_FromNativeBytes(addr, sizeof(off_t), -1); + break; +#endif + case Py_T_PID: + v = PyLong_FromPid(*(pid_t*)addr); + break; default: PyErr_SetString(PyExc_SystemError, "bad memberdescr type"); v = NULL; @@ -128,6 +175,48 @@ PyMember_GetOne(const char *obj_addr, PyMemberDef *l) return -1; \ } while (0) +#define SET_UNSIGNED_INT(N) do { \ + Py_ssize_t bytes = PyLong_AsNativeBytes(v, addr, (N), \ + Py_ASNATIVEBYTES_NATIVE_ENDIAN | \ + Py_ASNATIVEBYTES_ALLOW_INDEX | \ + Py_ASNATIVEBYTES_UNSIGNED_BUFFER | \ + Py_ASNATIVEBYTES_REJECT_NEGATIVE); \ + if (bytes < 0) { \ + return -1; \ + } \ + if ((size_t)bytes > (N)) { \ + PyErr_SetString(PyExc_OverflowError, "int too big to convert"); \ + return -1; \ + } \ + } while (0) + +#define SET_SIGNED_INT(N) do { \ + Py_ssize_t bytes = PyLong_AsNativeBytes(v, addr, (N), \ + Py_ASNATIVEBYTES_NATIVE_ENDIAN | \ + Py_ASNATIVEBYTES_ALLOW_INDEX); \ + if (bytes < 0) { \ + return -1; \ + } \ + if ((size_t)bytes > (N)) { \ + PyErr_SetString(PyExc_OverflowError, "int too big to convert"); \ + return -1; \ + } \ + } while (0) + +#define SET_COMBINED_INT(N) do { \ + Py_ssize_t bytes = PyLong_AsNativeBytes(v, addr, (N), \ + Py_ASNATIVEBYTES_NATIVE_ENDIAN | \ + Py_ASNATIVEBYTES_ALLOW_INDEX | \ + Py_ASNATIVEBYTES_UNSIGNED_BUFFER); \ + if (bytes < 0) { \ + return -1; \ + } \ + if ((size_t)bytes > (N)) { \ + PyErr_SetString(PyExc_OverflowError, "int too big to convert"); \ + return -1; \ + } \ + } while (0) + int PyMember_SetOne(char *addr, PyMemberDef *l, PyObject *v) { @@ -292,6 +381,14 @@ PyMember_SetOne(char *addr, PyMemberDef *l, PyObject *v) FT_ATOMIC_STORE_SSIZE_RELAXED(*(Py_ssize_t*)addr, ssize_val); break; } + case Py_T_SIZE: { + size_t value = PyLong_AsSize_t(v); + if (value == (size_t)-1 && PyErr_Occurred()) { + return -1; + } + *(size_t*)addr = value; + break; + } case Py_T_FLOAT:{ double double_val = PyFloat_AsDouble(v); if ((double_val == -1) && PyErr_Occurred()) @@ -361,6 +458,61 @@ PyMember_SetOne(char *addr, PyMemberDef *l, PyObject *v) } break; } + case Py_T_INT8: + SET_SIGNED_INT(1); + break; + case Py_T_UINT8: + SET_UNSIGNED_INT(1); + break; + case Py_T_INT8|Py_T_UINT8: + SET_COMBINED_INT(1); + break; + case Py_T_INT16: + SET_SIGNED_INT(2); + break; + case Py_T_UINT16: + SET_UNSIGNED_INT(2); + break; + case Py_T_INT16|Py_T_UINT16: + SET_COMBINED_INT(2); + break; + case Py_T_INT32: + SET_SIGNED_INT(4); + break; + case Py_T_UINT32: + SET_UNSIGNED_INT(4); + break; + case Py_T_INT32|Py_T_UINT32: + SET_COMBINED_INT(4); + break; + case Py_T_INT64: + SET_SIGNED_INT(8); + break; + case Py_T_UINT64: + SET_UNSIGNED_INT(8); + break; + case Py_T_INT64|Py_T_UINT64: + SET_COMBINED_INT(8); + break; + case Py_T_INTPTR: + SET_SIGNED_INT(sizeof(intptr_t)); + break; + case Py_T_UINTPTR: + SET_UNSIGNED_INT(sizeof(uintptr_t)); + break; +#ifndef MS_WINDOWS + case Py_T_OFF: + SET_SIGNED_INT(sizeof(off_t)); + break; +#endif + case Py_T_PID: { + pid_t value = PyLong_AsPid(v); + if (value == (pid_t)-1 && PyErr_Occurred()) { + return -1; + } + *(pid_t*)addr = value; + break; + } default: PyErr_Format(PyExc_SystemError, "bad memberdescr type for %s", l->name);