Blender V5.0
MEM_guardedalloc.h
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved.
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
39
40#ifndef __MEM_GUARDEDALLOC_H__
41#define __MEM_GUARDEDALLOC_H__
42
43/* Needed for uintptr_t and attributes, exception, don't use BLI anywhere else in `MEM_*` */
46
47#include <string.h>
48
49#ifdef __cplusplus
50extern "C" {
51#endif
52
53/* -------------------------------------------------------------------- */
65
71extern size_t (*MEM_allocN_len)(const void *vmemh) ATTR_WARN_UNUSED_RESULT;
72
78void MEM_freeN(void *vmemh);
79
80#if 0 /* UNUSED */
84extern short (*MEM_testN)(void *vmemh);
85#endif
86
91void *MEM_dupallocN(const void *vmemh) /* ATTR_MALLOC */ ATTR_WARN_UNUSED_RESULT;
92
98extern void *(*MEM_reallocN_id)(void *vmemh,
99 size_t len,
100 const char *str) /* ATTR_MALLOC */ ATTR_WARN_UNUSED_RESULT
102
106extern void *(*MEM_recallocN_id)(void *vmemh,
107 size_t len,
108 const char *str) /* ATTR_MALLOC */ ATTR_WARN_UNUSED_RESULT
110
111#define MEM_reallocN(vmemh, len) MEM_reallocN_id(vmemh, len, __func__)
112#define MEM_recallocN(vmemh, len) MEM_recallocN_id(vmemh, len, __func__)
113
119void *MEM_callocN(size_t len, const char *str) ATTR_WARN_UNUSED_RESULT ATTR_ALLOC_SIZE(1)
120 ATTR_NONNULL(2);
121
128 size_t size,
129 const char *str) /* ATTR_MALLOC */ ATTR_WARN_UNUSED_RESULT
131
136void *MEM_mallocN(size_t len, const char *str) /* ATTR_MALLOC */ ATTR_WARN_UNUSED_RESULT
138
145 size_t size,
146 const char *str) /* ATTR_MALLOC */ ATTR_WARN_UNUSED_RESULT
148
153void *MEM_mallocN_aligned(size_t len,
154 size_t alignment,
155 const char *str) /* ATTR_MALLOC */ ATTR_WARN_UNUSED_RESULT
157
161extern void *(*MEM_malloc_arrayN_aligned)(
162 size_t len,
163 size_t size,
164 size_t alignment,
165 const char *str) /* ATTR_MALLOC */ ATTR_WARN_UNUSED_RESULT ATTR_ALLOC_SIZE(1, 2)
167
171extern void *(*MEM_calloc_arrayN_aligned)(
172 size_t len,
173 size_t size,
174 size_t alignment,
175 const char *str) /* ATTR_MALLOC */ ATTR_WARN_UNUSED_RESULT ATTR_ALLOC_SIZE(1, 2)
176 ATTR_NONNULL(4);
177
178#ifdef __cplusplus
180# define MEM_SAFE_FREE(v) \
181 do { \
182 if (v) { \
183 MEM_freeN(v); \
184 (v) = nullptr; \
185 } \
186 } while (0)
187
189struct MEM_freeN_smart_ptr_deleter {
190 void operator()(void *pointer) const noexcept
191 {
192 MEM_SAFE_FREE(pointer);
193 }
194};
195
196#else
197# define MEM_SAFE_FREE(v) \
198 do { \
199 void **_v = (void **)&(v); \
200 if (*_v) { \
201 MEM_freeN(*_v); \
202 *_v = NULL; \
203 } \
204 } while (0)
205#endif
206
208
209/* -------------------------------------------------------------------- */
216
221extern void (*MEM_printmemlist_pydict)(void);
222
226extern void (*MEM_printmemlist)(void);
227
229extern void (*MEM_callbackmemlist)(void (*func)(void *));
230
232extern void (*MEM_printmemlist_stats)(void);
233
235extern void (*MEM_set_error_callback)(void (*func)(const char *));
236
242extern bool (*MEM_consistency_check)(void);
243
245extern void (*MEM_set_memory_debug)(void);
246
248extern size_t (*MEM_get_memory_in_use)(void);
250extern unsigned int (*MEM_get_memory_blocks_in_use)(void);
251
253extern void (*MEM_reset_peak_memory)(void);
254
256extern size_t (*MEM_get_peak_memory)(void) ATTR_WARN_UNUSED_RESULT;
257
259#define MEM_SIZE_OVERHEAD sizeof(size_t)
260#define MEM_SIZE_OPTIMAL(size) ((size) - MEM_SIZE_OVERHEAD)
261
262#ifndef NDEBUG
263extern const char *(*MEM_name_ptr)(void *vmemh);
272extern void (*MEM_name_ptr_set)(void *vmemh, const char *str) ATTR_NONNULL();
273#endif
274
280
287
298
309
311
312#ifdef __cplusplus
313}
314#endif /* __cplusplus */
315
316#ifdef __cplusplus
317
318# include <any>
319# include <memory>
320# include <new>
321# include <type_traits>
322# include <utility>
323
325
331# define MEM_MIN_CPP_ALIGNMENT \
332 (__STDCPP_DEFAULT_NEW_ALIGNMENT__ < alignof(void *) ? __STDCPP_DEFAULT_NEW_ALIGNMENT__ : \
333 alignof(void *))
334
335/* -------------------------------------------------------------------- */
351
352namespace mem_guarded::internal {
353/* Note that we intentionally don't care about a non-trivial default constructor here. */
354template<typename T>
355constexpr bool is_trivial_after_construction = std::is_trivially_copyable_v<T> &&
356 std::is_trivially_destructible_v<T>;
357} // namespace mem_guarded::internal
358
373template<typename T, typename... Args>
374inline T *MEM_new(const char *allocation_name, Args &&...args)
375{
377 sizeof(T), alignof(T), allocation_name, mem_guarded::internal::AllocationType::NEW_DELETE);
378 return new (buffer) T(std::forward<Args>(args)...);
379}
380
402template<typename T> inline T *MEM_new_for_free(const char *allocation_name)
403{
404 static_assert(mem_guarded::internal::is_trivial_after_construction<T>,
405 "MEM_new_for_free can only construct types that are trivially copyable and "
406 "destructible, use MEM_new instead.");
407 void *buffer;
408 /* There is no lower level #calloc with an alignment parameter, so unless the alignment is less
409 * than or equal to what we'd get by default, we have to fall back to #memset unfortunately. */
410 if (alignof(T) <= MEM_MIN_CPP_ALIGNMENT) {
411 buffer = MEM_callocN(sizeof(T), allocation_name);
412 }
413 else {
415 sizeof(T), alignof(T), allocation_name, mem_guarded::internal::AllocationType::ALLOC_FREE);
416 memset(buffer, 0, sizeof(T));
417 }
418 return new (buffer) T;
419}
420
430template<typename T> inline void MEM_delete(const T *ptr)
431{
432 static_assert(
433 !std::is_void_v<T>,
434 "MEM_delete on a void pointer is not possible, `static_cast` it to the correct type");
435 if (ptr == nullptr) {
436 return;
437 }
438 const void *complete_ptr = [ptr]() {
439 if constexpr (std::is_polymorphic_v<T>) {
440 /* Polymorphic objects lifetime can be managed with pointers to their most derived type or
441 * with pointers to any of their ancestor types in their hierarchy tree that define a virtual
442 * destructor, however ancestor pointers may differ in a offset from the same derived object.
443 * For freeing the correct memory allocated with #MEM_new, we need to ensure that the given
444 * pointer is equal to the pointer to the most derived object, which can be obtained with
445 * `dynamic_cast<void *>(ptr)`. */
446 return dynamic_cast<const void *>(ptr);
447 }
448 else {
449 return static_cast<const void *>(ptr);
450 }
451 }();
452 /* C++ allows destruction of `const` objects, so the pointer is allowed to be `const`. */
453 ptr->~T();
454 mem_guarded::internal::mem_freeN_ex(const_cast<void *>(complete_ptr),
456}
457
462# define MEM_SAFE_DELETE(v) \
463 do { \
464 if (v) { \
465 MEM_delete(v); \
466 (v) = nullptr; \
467 } \
468 } while (0)
469
471# define MEM_CXX_CLASS_ALLOC_FUNCS(_id) \
472 public: \
473 void *operator new(size_t num_bytes) \
474 { \
475 return mem_guarded::internal::mem_mallocN_aligned_ex( \
476 num_bytes, \
477 __STDCPP_DEFAULT_NEW_ALIGNMENT__, \
478 _id, \
479 mem_guarded::internal::AllocationType::NEW_DELETE); \
480 } \
481 void *operator new(size_t num_bytes, std::align_val_t alignment) \
482 { \
483 return mem_guarded::internal::mem_mallocN_aligned_ex( \
484 num_bytes, size_t(alignment), _id, mem_guarded::internal::AllocationType::NEW_DELETE); \
485 } \
486 void operator delete(void *mem) \
487 { \
488 if (mem) { \
489 mem_guarded::internal::mem_freeN_ex(mem, \
490 mem_guarded::internal::AllocationType::NEW_DELETE); \
491 } \
492 } \
493 void *operator new[](size_t num_bytes) \
494 { \
495 return mem_guarded::internal::mem_mallocN_aligned_ex( \
496 num_bytes, \
497 __STDCPP_DEFAULT_NEW_ALIGNMENT__, \
498 _id "[]", \
499 mem_guarded::internal::AllocationType::NEW_DELETE); \
500 } \
501 void *operator new[](size_t num_bytes, std::align_val_t alignment) \
502 { \
503 return mem_guarded::internal::mem_mallocN_aligned_ex( \
504 num_bytes, \
505 size_t(alignment), \
506 _id "[]", \
507 mem_guarded::internal::AllocationType::NEW_DELETE); \
508 } \
509 void operator delete[](void *mem) \
510 { \
511 if (mem) { \
512 mem_guarded::internal::mem_freeN_ex(mem, \
513 mem_guarded::internal::AllocationType::NEW_DELETE); \
514 } \
515 } \
516 void *operator new(size_t /*count*/, void *ptr) \
517 { \
518 return ptr; \
519 } \
520 \
525 void operator delete(void * /*ptr_to_free*/, void * /*ptr*/) {}
526
528
529/* -------------------------------------------------------------------- */
544
556template<typename T> inline T *MEM_callocN(const char *allocation_name)
557{
558# ifdef _MSC_VER
559 static_assert(std::is_trivially_constructible_v<T>,
560 "For non-trivial types, MEM_new must be used.");
561# else
562 static_assert(std::is_trivial_v<T>, "For non-trivial types, MEM_new must be used.");
563# endif
564 return static_cast<T *>(MEM_calloc_arrayN_aligned(1, sizeof(T), alignof(T), allocation_name));
565}
566
572template<typename T> inline T *MEM_calloc_arrayN(const size_t length, const char *allocation_name)
573{
574# ifdef _MSC_VER
575 static_assert(std::is_trivially_constructible_v<T>,
576 "For non-trivial types, MEM_new must be used.");
577# else
578 static_assert(std::is_trivial_v<T>, "For non-trivial types, MEM_new must be used.");
579# endif
580 return static_cast<T *>(
581 MEM_calloc_arrayN_aligned(length, sizeof(T), alignof(T), allocation_name));
582}
583
595template<typename T> inline T *MEM_mallocN(const char *allocation_name)
596{
597# ifdef _MSC_VER
598 static_assert(std::is_trivially_constructible_v<T>,
599 "For non-trivial types, MEM_new must be used.");
600# else
601 static_assert(std::is_trivial_v<T>, "For non-trivial types, MEM_new must be used.");
602# endif
603 return static_cast<T *>(MEM_malloc_arrayN_aligned(1, sizeof(T), alignof(T), allocation_name));
604}
605
611template<typename T> inline T *MEM_malloc_arrayN(const size_t length, const char *allocation_name)
612{
613# ifdef _MSC_VER
614 static_assert(std::is_trivially_constructible_v<T>,
615 "For non-trivial types, MEM_new must be used.");
616# else
617 static_assert(std::is_trivial_v<T>, "For non-trivial types, MEM_new must be used.");
618# endif
619 return static_cast<T *>(
620 MEM_malloc_arrayN_aligned(length, sizeof(T), alignof(T), allocation_name));
621}
622
634template<typename T> inline T *MEM_dupallocN(const char *allocation_name, const T &other)
635{
636# ifdef _MSC_VER
637 static_assert(std::is_trivially_assignable_v<T &, T> && std::is_trivially_destructible_v<T>,
638 "MEM_dupallocN can only duplicate types that are trivially copyable and "
639 "destructible, use MEM_new instead.");
640# else
641 static_assert(mem_guarded::internal::is_trivial_after_construction<T>,
642 "MEM_dupallocN can only duplicate types that are trivially copyable and "
643 "destructible, use MEM_new instead.");
644# endif
645 T *new_object = static_cast<T *>(MEM_mallocN_aligned(sizeof(T), alignof(T), allocation_name));
646 if (new_object) {
647 memcpy(new_object, &other, sizeof(T));
648 }
649 return new_object;
650}
651
652template<typename T> inline void MEM_freeN(T *ptr)
653{
654# ifdef _MSC_VER
655 static_assert(std::is_trivially_destructible_v<T>,
656 "MEM_freeN can only free types that are trivially copyable and destructible, use "
657 "MEM_delete instead.");
658# else
659 static_assert(mem_guarded::internal::is_trivial_after_construction<T>,
660 "MEM_freeN can only free types that are trivially copyable and destructible, use "
661 "MEM_delete instead.");
662# endif
663 mem_guarded::internal::mem_freeN_ex(const_cast<void *>(static_cast<const void *>(ptr)),
665}
666
668
678template<typename T, typename... Args> T &MEM_construct_leak_detection_data(Args &&...args)
679{
680 std::shared_ptr<T> data = std::make_shared<T>(std::forward<Args>(args)...);
681 std::any any_data = std::make_any<std::shared_ptr<T>>(data);
683 return *data;
684}
685
686#endif /* __cplusplus */
687
688#endif /* __MEM_GUARDEDALLOC_H__ */
#define ATTR_WARN_UNUSED_RESULT
#define ATTR_ALLOC_SIZE(...)
#define ATTR_NONNULL(...)
void MEM_use_guarded_allocator(void)
Definition mallocn.cc:204
void *(* MEM_malloc_arrayN_aligned)(size_t len, size_t size, size_t alignment, const char *str) ATTR_WARN_UNUSED_RESULT ATTR_ALLOC_SIZE(1
Definition mallocn.cc:55
void * MEM_calloc_arrayN(size_t len, size_t size, const char *str) ATTR_WARN_UNUSED_RESULT ATTR_ALLOC_SIZE(1
void MEM_enable_fail_on_memleak(void)
#define MEM_SAFE_FREE(v)
void * MEM_callocN(size_t len, const char *str) ATTR_WARN_UNUSED_RESULT ATTR_ALLOC_SIZE(1) ATTR_NONNULL(2)
Definition mallocn.cc:118
void *(* MEM_calloc_arrayN_aligned)(size_t len, size_t size, size_t alignment, const char *str) ATTR_WARN_UNUSED_RESULT ATTR_ALLOC_SIZE(1
Definition mallocn.cc:59
void MEM_init_memleak_detection(void)
void * MEM_mallocN_aligned(size_t len, size_t alignment, const char *str) ATTR_WARN_UNUSED_RESULT ATTR_ALLOC_SIZE(1) ATTR_NONNULL(3)
Definition mallocn.cc:138
void MEM_use_lockfree_allocator(void)
Definition mallocn.cc:163
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
void * MEM_malloc_arrayN(size_t len, size_t size, const char *str) ATTR_WARN_UNUSED_RESULT ATTR_ALLOC_SIZE(1
void * MEM_mallocN(size_t len, const char *str) ATTR_WARN_UNUSED_RESULT ATTR_ALLOC_SIZE(1) ATTR_NONNULL(2)
Definition mallocn.cc:128
void * MEM_dupallocN(const void *vmemh) ATTR_WARN_UNUSED_RESULT
Definition mallocn.cc:143
BMesh const char void * data
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
SIMD_FORCE_INLINE btVector3 operator()(const btVector3 &x) const
Return the transform of the vector.
Definition btTransform.h:90
#define str(s)
float length(VecOp< float, D >) RET
void * MEM_mallocN(size_t len, const char *str)
Definition mallocn.cc:128
size_t(* MEM_get_peak_memory)(void)
Definition mallocn.cc:73
void * MEM_calloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:123
void * MEM_mallocN_aligned(size_t len, size_t alignment, const char *str)
Definition mallocn.cc:138
void(* MEM_reset_peak_memory)(void)
Definition mallocn.cc:72
void(* MEM_name_ptr_set)(void *vmemh, const char *str)
Definition mallocn.cc:79
size_t(* MEM_get_memory_in_use)(void)
Definition mallocn.cc:70
void *(* MEM_calloc_arrayN_aligned)(size_t len, size_t size, size_t alignment, const char *str)
Definition mallocn.cc:59
void(* MEM_printmemlist_stats)(void)
Definition mallocn.cc:66
void(* MEM_set_memory_debug)(void)
Definition mallocn.cc:69
void * MEM_malloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:133
void(* MEM_set_error_callback)(void(*func)(const char *))
Definition mallocn.cc:67
size_t(* MEM_allocN_len)(const void *vmemh)
Definition mallocn.cc:36
bool(* MEM_consistency_check)(void)
Definition mallocn.cc:68
void *(* MEM_malloc_arrayN_aligned)(size_t len, size_t size, size_t alignment, const char *str)
Definition mallocn.cc:55
void(* MEM_printmemlist_pydict)(void)
Definition mallocn.cc:63
uint(* MEM_get_memory_blocks_in_use)(void)
Definition mallocn.cc:71
void(* MEM_callbackmemlist)(void(*func)(void *))
Definition mallocn.cc:65
void(* MEM_printmemlist)(void)
Definition mallocn.cc:64
#define T
void add_memleak_data(std::any data)
void(* mem_freeN_ex)(void *vmemh, AllocationType allocation_type)
Definition mallocn.cc:37
void *(* mem_mallocN_aligned_ex)(size_t len, size_t alignment, const char *str, AllocationType allocation_type)
Definition mallocn.cc:50
uint len
PointerRNA * ptr
Definition wm_files.cc:4238