2019-05-24 12:01:38 -03:00
|
|
|
#ifndef Py_INTERNAL_PYMEM_H
|
|
|
|
#define Py_INTERNAL_PYMEM_H
|
2023-12-07 15:33:40 -04:00
|
|
|
|
2024-02-20 14:04:37 -04:00
|
|
|
#include "pycore_llist.h" // struct llist_node
|
2023-12-07 15:33:40 -04:00
|
|
|
#include "pycore_lock.h" // PyMutex
|
|
|
|
|
2017-09-08 02:51:28 -03:00
|
|
|
#ifdef __cplusplus
|
|
|
|
extern "C" {
|
|
|
|
#endif
|
|
|
|
|
2019-04-17 18:02:26 -03:00
|
|
|
#ifndef Py_BUILD_CORE
|
|
|
|
# error "this header requires Py_BUILD_CORE define"
|
2018-10-31 16:19:24 -03:00
|
|
|
#endif
|
|
|
|
|
2023-07-24 15:48:06 -03:00
|
|
|
// Try to get the allocators name set by _PyMem_SetupAllocators().
|
|
|
|
// Return NULL if unknown.
|
2023-07-25 00:16:28 -03:00
|
|
|
// Export for '_testinternalcapi' shared extension.
|
2023-07-24 15:48:06 -03:00
|
|
|
PyAPI_FUNC(const char*) _PyMem_GetCurrentAllocatorName(void);
|
2017-09-08 02:51:28 -03:00
|
|
|
|
2023-07-24 15:48:06 -03:00
|
|
|
// strdup() using PyMem_RawMalloc()
|
|
|
|
extern char* _PyMem_RawStrdup(const char *str);
|
|
|
|
|
|
|
|
// strdup() using PyMem_Malloc().
|
2023-07-25 00:16:28 -03:00
|
|
|
// Export for '_pickle ' shared extension.
|
2023-07-24 15:48:06 -03:00
|
|
|
PyAPI_FUNC(char*) _PyMem_Strdup(const char *str);
|
|
|
|
|
|
|
|
// wcsdup() using PyMem_RawMalloc()
|
|
|
|
extern wchar_t* _PyMem_RawWcsdup(const wchar_t *str);
|
2018-10-31 16:19:24 -03:00
|
|
|
|
2022-11-11 19:30:46 -04:00
|
|
|
typedef struct {
|
|
|
|
/* We tag each block with an API ID in order to tag API violations */
|
|
|
|
char api_id;
|
|
|
|
PyMemAllocatorEx alloc;
|
|
|
|
} debug_alloc_api_t;
|
|
|
|
|
|
|
|
struct _pymem_allocators {
|
2023-12-07 15:33:40 -04:00
|
|
|
PyMutex mutex;
|
2022-11-11 19:30:46 -04:00
|
|
|
struct {
|
|
|
|
PyMemAllocatorEx raw;
|
|
|
|
PyMemAllocatorEx mem;
|
|
|
|
PyMemAllocatorEx obj;
|
|
|
|
} standard;
|
|
|
|
struct {
|
|
|
|
debug_alloc_api_t raw;
|
|
|
|
debug_alloc_api_t mem;
|
|
|
|
debug_alloc_api_t obj;
|
|
|
|
} debug;
|
2024-01-16 17:42:15 -04:00
|
|
|
int is_debug_enabled;
|
2022-11-11 19:30:46 -04:00
|
|
|
PyObjectArenaAllocator obj_arena;
|
|
|
|
};
|
|
|
|
|
2024-02-20 14:04:37 -04:00
|
|
|
struct _Py_mem_interp_free_queue {
|
|
|
|
int has_work; // true if the queue is not empty
|
|
|
|
PyMutex mutex; // protects the queue
|
|
|
|
struct llist_node head; // queue of _mem_work_chunk items
|
|
|
|
};
|
2022-11-11 19:30:46 -04:00
|
|
|
|
2018-10-31 16:19:24 -03:00
|
|
|
/* Set the memory allocator of the specified domain to the default.
|
|
|
|
Save the old allocator into *old_alloc if it's non-NULL.
|
|
|
|
Return on success, or return -1 if the domain is unknown. */
|
2023-07-24 22:49:28 -03:00
|
|
|
extern int _PyMem_SetDefaultAllocator(
|
2018-10-31 16:19:24 -03:00
|
|
|
PyMemAllocatorDomain domain,
|
|
|
|
PyMemAllocatorEx *old_alloc);
|
|
|
|
|
2019-10-07 17:31:42 -03:00
|
|
|
/* Special bytes broadcast into debug memory blocks at appropriate times.
|
|
|
|
Strings of these are unlikely to be valid addresses, floats, ints or
|
|
|
|
7-bit ASCII.
|
|
|
|
|
|
|
|
- PYMEM_CLEANBYTE: clean (newly allocated) memory
|
|
|
|
- PYMEM_DEADBYTE dead (newly freed) memory
|
|
|
|
- PYMEM_FORBIDDENBYTE: untouchable bytes at each end of a block
|
|
|
|
|
2019-10-10 04:32:13 -03:00
|
|
|
Byte patterns 0xCB, 0xDB and 0xFB have been replaced with 0xCD, 0xDD and
|
2024-01-12 18:25:52 -04:00
|
|
|
0xFD to use the same values as Windows CRT debug malloc() and free().
|
2019-10-07 17:31:42 -03:00
|
|
|
If modified, _PyMem_IsPtrFreed() should be updated as well. */
|
|
|
|
#define PYMEM_CLEANBYTE 0xCD
|
|
|
|
#define PYMEM_DEADBYTE 0xDD
|
|
|
|
#define PYMEM_FORBIDDENBYTE 0xFD
|
|
|
|
|
2019-04-11 06:33:27 -03:00
|
|
|
/* Heuristic checking if a pointer value is newly allocated
|
2019-10-07 13:42:01 -03:00
|
|
|
(uninitialized), newly freed or NULL (is equal to zero).
|
|
|
|
|
|
|
|
The pointer is not dereferenced, only the pointer value is checked.
|
2019-04-11 06:33:27 -03:00
|
|
|
|
|
|
|
The heuristic relies on the debug hooks on Python memory allocators which
|
2019-04-11 08:01:15 -03:00
|
|
|
fills newly allocated memory with CLEANBYTE (0xCD) and newly freed memory
|
|
|
|
with DEADBYTE (0xDD). Detect also "untouchable bytes" marked
|
|
|
|
with FORBIDDENBYTE (0xFD). */
|
2021-05-21 14:19:54 -03:00
|
|
|
static inline int _PyMem_IsPtrFreed(const void *ptr)
|
2019-04-11 06:33:27 -03:00
|
|
|
{
|
|
|
|
uintptr_t value = (uintptr_t)ptr;
|
|
|
|
#if SIZEOF_VOID_P == 8
|
2019-10-07 13:42:01 -03:00
|
|
|
return (value == 0
|
|
|
|
|| value == (uintptr_t)0xCDCDCDCDCDCDCDCD
|
2019-04-11 08:01:15 -03:00
|
|
|
|| value == (uintptr_t)0xDDDDDDDDDDDDDDDD
|
|
|
|
|| value == (uintptr_t)0xFDFDFDFDFDFDFDFD);
|
2019-04-11 06:33:27 -03:00
|
|
|
#elif SIZEOF_VOID_P == 4
|
2019-10-07 13:42:01 -03:00
|
|
|
return (value == 0
|
|
|
|
|| value == (uintptr_t)0xCDCDCDCD
|
2019-04-11 08:01:15 -03:00
|
|
|
|| value == (uintptr_t)0xDDDDDDDD
|
|
|
|
|| value == (uintptr_t)0xFDFDFDFD);
|
2019-04-11 06:33:27 -03:00
|
|
|
#else
|
|
|
|
# error "unknown pointer size"
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2023-07-24 22:49:28 -03:00
|
|
|
extern int _PyMem_GetAllocatorName(
|
2019-05-17 10:20:52 -03:00
|
|
|
const char *name,
|
|
|
|
PyMemAllocatorName *allocator);
|
|
|
|
|
|
|
|
/* Configure the Python memory allocators.
|
|
|
|
Pass PYMEM_ALLOCATOR_DEFAULT to use default allocators.
|
|
|
|
PYMEM_ALLOCATOR_NOT_SET does nothing. */
|
2023-07-24 22:49:28 -03:00
|
|
|
extern int _PyMem_SetupAllocators(PyMemAllocatorName allocator);
|
2019-05-17 10:20:52 -03:00
|
|
|
|
2024-01-16 17:42:15 -04:00
|
|
|
/* Is the debug allocator enabled? */
|
|
|
|
extern int _PyMem_DebugEnabled(void);
|
2020-02-04 20:11:10 -04:00
|
|
|
|
2024-02-20 14:04:37 -04:00
|
|
|
// Enqueue a pointer to be freed possibly after some delay.
|
|
|
|
extern void _PyMem_FreeDelayed(void *ptr);
|
|
|
|
|
2024-03-08 13:56:36 -04:00
|
|
|
// Enqueue an object to be freed possibly after some delay
|
2024-11-21 12:41:19 -04:00
|
|
|
#ifdef Py_GIL_DISABLED
|
|
|
|
extern void _PyObject_XDecRefDelayed(PyObject *obj);
|
|
|
|
#else
|
|
|
|
static inline void _PyObject_XDecRefDelayed(PyObject *obj)
|
|
|
|
{
|
|
|
|
Py_XDECREF(obj);
|
|
|
|
}
|
|
|
|
#endif
|
2024-03-08 13:56:36 -04:00
|
|
|
|
2024-02-20 14:04:37 -04:00
|
|
|
// Periodically process delayed free requests.
|
|
|
|
extern void _PyMem_ProcessDelayed(PyThreadState *tstate);
|
|
|
|
|
2024-11-21 12:41:19 -04:00
|
|
|
|
|
|
|
// Periodically process delayed free requests when the world is stopped.
|
|
|
|
// Notify of any objects whic should be freeed.
|
|
|
|
typedef void (*delayed_dealloc_cb)(PyObject *, void *);
|
|
|
|
extern void _PyMem_ProcessDelayedNoDealloc(PyThreadState *tstate,
|
|
|
|
delayed_dealloc_cb cb, void *state);
|
|
|
|
|
2024-02-20 14:04:37 -04:00
|
|
|
// Abandon all thread-local delayed free requests and push them to the
|
|
|
|
// interpreter's queue.
|
|
|
|
extern void _PyMem_AbandonDelayed(PyThreadState *tstate);
|
|
|
|
|
|
|
|
// On interpreter shutdown, frees all delayed free requests.
|
|
|
|
extern void _PyMem_FiniDelayed(PyInterpreterState *interp);
|
|
|
|
|
2017-09-08 02:51:28 -03:00
|
|
|
#ifdef __cplusplus
|
|
|
|
}
|
|
|
|
#endif
|
2023-07-22 12:04:34 -03:00
|
|
|
#endif // !Py_INTERNAL_PYMEM_H
|