diff --git a/Doc/c-api/memory.rst b/Doc/c-api/memory.rst index aa2ef499bddaf3..f8c6b48ec62176 100644 --- a/Doc/c-api/memory.rst +++ b/Doc/c-api/memory.rst @@ -199,6 +199,31 @@ zero bytes. If *p* is ``NULL``, no operation is performed. +The following type-oriented macros are provided for convenience. Note that +*TYPE* refers to any C type. + +.. c:macro:: PyMem_RawNew(TYPE, n) + + Same as :c:func:`PyMem_RawMalloc`, but allocates ``(n * sizeof(TYPE))`` + bytes of memory. Returns a pointer cast to ``TYPE*``. The memory will + not have been initialized in any way. + + .. versionadded:: next + + +.. c:macro:: PyMem_RawResize(p, TYPE, n) + + Same as :c:func:`PyMem_RawRealloc`, but the memory block is resized to + ``(n * sizeof(TYPE))`` bytes. Returns a pointer cast to ``TYPE*``. + On return, *p* will be a pointer to the new memory area, or ``NULL`` in + the event of failure. + + This is a C preprocessor macro; *p* is always reassigned. Save the original + value of *p* to avoid losing memory when handling errors. + + .. versionadded:: next + + .. _memoryinterface: Memory Interface diff --git a/Doc/data/stable_abi.dat b/Doc/data/stable_abi.dat index 6f9d27297e8f65..97ee54ed08a838 100644 --- a/Doc/data/stable_abi.dat +++ b/Doc/data/stable_abi.dat @@ -407,7 +407,9 @@ func,PyMem_Malloc,3.2,, func,PyMem_RawCalloc,3.13,, func,PyMem_RawFree,3.13,, func,PyMem_RawMalloc,3.13,, +macro,PyMem_RawNew,3.14,, func,PyMem_RawRealloc,3.13,, +macro,PyMem_RawResize,3.14,, func,PyMem_Realloc,3.2,, type,PyMemberDef,3.2,,full-abi data,PyMemberDescr_Type,3.2,, diff --git a/Doc/whatsnew/3.14.rst b/Doc/whatsnew/3.14.rst index 958efbe73c1c27..f29ce9cc2346b1 100644 --- a/Doc/whatsnew/3.14.rst +++ b/Doc/whatsnew/3.14.rst @@ -907,13 +907,17 @@ New features test if two strings are equal. (Contributed by Victor Stinner in :gh:`124502`.) - * Add :c:func:`PyType_Freeze` function to make a type immutable. (Contributed by Victor Stinner in :gh:`121654`.) * Add :c:func:`PyUnstable_Object_EnableDeferredRefcount` for enabling deferred reference counting, as outlined in :pep:`703`. +* Add the :c:macro:`PyMem_RawNew` and :c:macro:`PyMem_RawResize` convenience + macros to the limited C API. + (Contributed by Bénédikt Tran in :gh:`XXX`.) + + Porting to Python 3.14 ---------------------- diff --git a/Include/pymem.h b/Include/pymem.h index a80da99e1dd7fc..1f66a71e3dae4d 100644 --- a/Include/pymem.h +++ b/Include/pymem.h @@ -60,20 +60,21 @@ PyAPI_FUNC(void) PyMem_Free(void *ptr); * overflow checking is always done. */ -#define PyMem_New(type, n) \ - ( ((size_t)(n) > PY_SSIZE_T_MAX / sizeof(type)) ? NULL : \ - ( (type *) PyMem_Malloc((n) * sizeof(type)) ) ) +#define PyMem_New(TYPE, N) \ + (((size_t)(N) <= PY_SSIZE_T_MAX / sizeof(TYPE)) \ + ? (TYPE *)PyMem_Malloc((N) * sizeof(TYPE)) \ + : NULL) /* - * The value of (p) is always clobbered by this macro regardless of success. - * The caller MUST check if (p) is NULL afterwards and deal with the memory - * error if so. This means the original value of (p) MUST be saved for the + * The value of (PTR) is always clobbered by this macro regardless of success. + * The caller MUST check if (PTR) is NULL afterwards and deal with the memory + * error if so. This means the original value of (PTR) MUST be saved for the * caller's memory error handler to not lose track of it. */ -#define PyMem_Resize(p, type, n) \ - ( (p) = ((size_t)(n) > PY_SSIZE_T_MAX / sizeof(type)) ? NULL : \ - (type *) PyMem_Realloc((p), (n) * sizeof(type)) ) - +#define PyMem_Resize(PTR, TYPE, N) \ + ((PTR) = ((size_t)(N) <= PY_SSIZE_T_MAX / sizeof(TYPE)) \ + ? (TYPE *)PyMem_Realloc((PTR), (N) * sizeof(TYPE)) \ + : NULL) // Deprecated aliases only kept for backward compatibility. // PyMem_Del and PyMem_DEL are defined with no parameter to be able to use @@ -86,7 +87,6 @@ PyAPI_FUNC(void) PyMem_Free(void *ptr); #define PyMem_Del(p) PyMem_Free((p)) #define PyMem_DEL(p) PyMem_Free((p)) - #if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x030d0000 // Memory allocator which doesn't require the GIL to be held. // Usually, it's just a thin wrapper to functions of the standard C library: @@ -98,6 +98,18 @@ PyAPI_FUNC(void *) PyMem_RawRealloc(void *ptr, size_t new_size); PyAPI_FUNC(void) PyMem_RawFree(void *ptr); #endif +#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x030e0000 +#define PyMem_RawNew(TYPE, N) \ + (((size_t)(N) <= PY_SSIZE_T_MAX / sizeof(TYPE)) \ + ? (TYPE *)PyMem_RawMalloc((N) * sizeof(TYPE)) \ + : NULL) + +#define PyMem_RawResize(PTR, TYPE, N) \ + ((PTR) = ((size_t)(N) <= PY_SSIZE_T_MAX / sizeof(TYPE)) \ + ? (TYPE *)PyMem_RawRealloc((PTR), (N) * sizeof(TYPE)) \ + : NULL) +#endif + #ifndef Py_LIMITED_API # define Py_CPYTHON_PYMEM_H # include "cpython/pymem.h" diff --git a/Misc/stable_abi.toml b/Misc/stable_abi.toml index f9e51f0683c965..a8cc1a2613156c 100644 --- a/Misc/stable_abi.toml +++ b/Misc/stable_abi.toml @@ -2540,3 +2540,7 @@ added = '3.14' [function.PyType_Freeze] added = '3.14' +[macro.PyMem_RawNew] + added = '3.14' +[macro.PyMem_RawResize] + added = '3.14'