| 
									
										
										
										
											2019-05-24 17:01:38 +02:00
										 |  |  | #ifndef Py_INTERNAL_PYMEM_H
 | 
					
						
							|  |  |  | #define Py_INTERNAL_PYMEM_H
 | 
					
						
							| 
									
										
										
										
											2023-12-07 14:33:40 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-20 13:04:37 -05:00
										 |  |  | #include "pycore_llist.h"           // struct llist_node
 | 
					
						
							| 
									
										
										
										
											2023-12-07 14:33:40 -05:00
										 |  |  | #include "pycore_lock.h"            // PyMutex
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-07 23:51:28 -06:00
										 |  |  | #ifdef __cplusplus
 | 
					
						
							|  |  |  | extern "C" { | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 23:02:26 +02:00
										 |  |  | #ifndef Py_BUILD_CORE
 | 
					
						
							|  |  |  | #  error "this header requires Py_BUILD_CORE define"
 | 
					
						
							| 
									
										
										
										
											2018-10-31 20:19:24 +01:00
										 |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-24 20:48:06 +02:00
										 |  |  | // Try to get the allocators name set by _PyMem_SetupAllocators().
 | 
					
						
							|  |  |  | // Return NULL if unknown.
 | 
					
						
							| 
									
										
										
										
											2023-07-25 05:16:28 +02:00
										 |  |  | // Export for '_testinternalcapi' shared extension.
 | 
					
						
							| 
									
										
										
										
											2023-07-24 20:48:06 +02:00
										 |  |  | PyAPI_FUNC(const char*) _PyMem_GetCurrentAllocatorName(void); | 
					
						
							| 
									
										
										
										
											2017-09-07 23:51:28 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-24 20:48:06 +02:00
										 |  |  | // strdup() using PyMem_RawMalloc()
 | 
					
						
							|  |  |  | extern char* _PyMem_RawStrdup(const char *str); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // strdup() using PyMem_Malloc().
 | 
					
						
							| 
									
										
										
										
											2023-07-25 05:16:28 +02:00
										 |  |  | // Export for '_pickle ' shared extension.
 | 
					
						
							| 
									
										
										
										
											2023-07-24 20:48:06 +02: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 20:19:24 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-11 16:30:46 -07: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 14:33:40 -05:00
										 |  |  |     PyMutex mutex; | 
					
						
							| 
									
										
										
										
											2022-11-11 16:30:46 -07: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 16:42:15 -05:00
										 |  |  |     int is_debug_enabled; | 
					
						
							| 
									
										
										
										
											2022-11-11 16:30:46 -07:00
										 |  |  |     PyObjectArenaAllocator obj_arena; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-20 13:04:37 -05: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 16:30:46 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-31 20:19:24 +01: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-25 03:49:28 +02:00
										 |  |  | extern int _PyMem_SetDefaultAllocator( | 
					
						
							| 
									
										
										
										
											2018-10-31 20:19:24 +01:00
										 |  |  |     PyMemAllocatorDomain domain, | 
					
						
							|  |  |  |     PyMemAllocatorEx *old_alloc); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-07 22:31:42 +02: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 09:32:13 +02:00
										 |  |  |    Byte patterns 0xCB, 0xDB and 0xFB have been replaced with 0xCD, 0xDD and | 
					
						
							| 
									
										
										
										
											2024-01-12 17:25:52 -05:00
										 |  |  |    0xFD to use the same values as Windows CRT debug malloc() and free(). | 
					
						
							| 
									
										
										
										
											2019-10-07 22:31:42 +02: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 11:33:27 +02:00
										 |  |  | /* Heuristic checking if a pointer value is newly allocated
 | 
					
						
							| 
									
										
										
										
											2019-10-07 18:42:01 +02:00
										 |  |  |    (uninitialized), newly freed or NULL (is equal to zero). | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |    The pointer is not dereferenced, only the pointer value is checked. | 
					
						
							| 
									
										
										
										
											2019-04-11 11:33:27 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |    The heuristic relies on the debug hooks on Python memory allocators which | 
					
						
							| 
									
										
										
										
											2019-04-11 13:01:15 +02: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 19:19:54 +02:00
										 |  |  | static inline int _PyMem_IsPtrFreed(const void *ptr) | 
					
						
							| 
									
										
										
										
											2019-04-11 11:33:27 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     uintptr_t value = (uintptr_t)ptr; | 
					
						
							|  |  |  | #if SIZEOF_VOID_P == 8
 | 
					
						
							| 
									
										
										
										
											2019-10-07 18:42:01 +02:00
										 |  |  |     return (value == 0 | 
					
						
							|  |  |  |             || value == (uintptr_t)0xCDCDCDCDCDCDCDCD | 
					
						
							| 
									
										
										
										
											2019-04-11 13:01:15 +02:00
										 |  |  |             || value == (uintptr_t)0xDDDDDDDDDDDDDDDD | 
					
						
							|  |  |  |             || value == (uintptr_t)0xFDFDFDFDFDFDFDFD); | 
					
						
							| 
									
										
										
										
											2019-04-11 11:33:27 +02:00
										 |  |  | #elif SIZEOF_VOID_P == 4
 | 
					
						
							| 
									
										
										
										
											2019-10-07 18:42:01 +02:00
										 |  |  |     return (value == 0 | 
					
						
							|  |  |  |             || value == (uintptr_t)0xCDCDCDCD | 
					
						
							| 
									
										
										
										
											2019-04-11 13:01:15 +02:00
										 |  |  |             || value == (uintptr_t)0xDDDDDDDD | 
					
						
							|  |  |  |             || value == (uintptr_t)0xFDFDFDFD); | 
					
						
							| 
									
										
										
										
											2019-04-11 11:33:27 +02:00
										 |  |  | #else
 | 
					
						
							|  |  |  | #  error "unknown pointer size"
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-25 03:49:28 +02:00
										 |  |  | extern int _PyMem_GetAllocatorName( | 
					
						
							| 
									
										
										
										
											2019-05-17 15:20:52 +02: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-25 03:49:28 +02:00
										 |  |  | extern int _PyMem_SetupAllocators(PyMemAllocatorName allocator); | 
					
						
							| 
									
										
										
										
											2019-05-17 15:20:52 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-16 16:42:15 -05:00
										 |  |  | /* Is the debug allocator enabled? */ | 
					
						
							|  |  |  | extern int _PyMem_DebugEnabled(void); | 
					
						
							| 
									
										
										
										
											2020-02-05 01:11:10 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-20 13:04:37 -05:00
										 |  |  | // Enqueue a pointer to be freed possibly after some delay.
 | 
					
						
							|  |  |  | extern void _PyMem_FreeDelayed(void *ptr); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-08 09:56:36 -08:00
										 |  |  | // Enqueue an object to be freed possibly after some delay
 | 
					
						
							|  |  |  | extern void _PyObject_FreeDelayed(void *ptr); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-20 13:04:37 -05:00
										 |  |  | // Periodically process delayed free requests.
 | 
					
						
							|  |  |  | extern void _PyMem_ProcessDelayed(PyThreadState *tstate); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // 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-07 23:51:28 -06:00
										 |  |  | #ifdef __cplusplus
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2023-07-22 17:04:34 +02:00
										 |  |  | #endif  // !Py_INTERNAL_PYMEM_H
 |