MEM_guardedalloc: Refactor to add more type-safety.

The main goal of these changes are to improve static (i.e. build-time)
checks on whether a given data can be allocated and freed with `malloc`
and `free` (C-style), or requires proper C++-style construction and
destruction (`new` and `delete`).

* Add new `MEM_malloc_arrayN_aligned` API.
* Make `MEM_freeN` a template function in C++, which does static assert on
  type triviality.
* Add `MEM_SAFE_DELETE`, similar to `MEM_SAFE_FREE` but calling
  `MEM_delete`.

The changes to `MEM_freeN` was painful and useful, as it allowed to fix a bunch
of invalid calls in existing codebase already.

It also highlighted a fair amount of places where it is called to free incomplete
type pointers, which is likely a sign of badly designed code (there should
rather be an API to destroy and free these data then, if the data type is not fully
publicly exposed). For now, these are 'worked around' by explicitly casting the
freed pointers to `void *` in these cases - which also makes them easy to search for.
Some of these will be addressed separately (see blender/blender!134765).

Finally, MSVC seems to consider structs defining new/delete operators (e.g. by
using the `MEM_CXX_CLASS_ALLOC_FUNCS` macro) as non-trivial. This does not
seem to follow the definition of type triviality, so for now static type checking in
`MEM_freeN` has been disabled for Windows. We'll likely have to do the same
with type-safe `MEM_[cm]allocN` API being worked on in blender/blender!134771

Based on ideas from Brecht in blender/blender!134452

Pull Request: https://projects.blender.org/blender/blender/pulls/134463
This commit is contained in:
Bastien Montagne
2025-02-20 10:37:10 +01:00
committed by Bastien Montagne
parent 6be8dd16e7
commit 48e26c3afe
32 changed files with 203 additions and 62 deletions

View File

@@ -61,7 +61,7 @@ template<typename T> class GuardedAllocator {
util_guarded_mem_free(n * sizeof(T)); util_guarded_mem_free(n * sizeof(T));
if (p != nullptr) { if (p != nullptr) {
#ifdef WITH_BLENDER_GUARDEDALLOC #ifdef WITH_BLENDER_GUARDEDALLOC
MEM_freeN(p); MEM_freeN(const_cast<void *>(static_cast<const void *>(p)));
#else #else
free(p); free(p);
#endif #endif

View File

@@ -69,7 +69,7 @@ template<int SIZE, typename T> class ccl_try_align(16) StackAllocator
if (p < data_ || p >= data_ + SIZE) { if (p < data_ || p >= data_ + SIZE) {
util_guarded_mem_free(n * sizeof(T)); util_guarded_mem_free(n * sizeof(T));
#ifdef WITH_BLENDER_GUARDEDALLOC #ifdef WITH_BLENDER_GUARDEDALLOC
MEM_freeN(p); MEM_freeN(static_cast<void *>(p));
#else #else
free(p); free(p);
#endif #endif

View File

@@ -136,6 +136,16 @@ void *MEM_mallocN_aligned(size_t len,
const char *str) /* ATTR_MALLOC */ ATTR_WARN_UNUSED_RESULT const char *str) /* ATTR_MALLOC */ ATTR_WARN_UNUSED_RESULT
ATTR_ALLOC_SIZE(1) ATTR_NONNULL(3); ATTR_ALLOC_SIZE(1) ATTR_NONNULL(3);
/**
* Allocate an aligned block of memory that remains uninitialized.
*/
extern void *(*MEM_malloc_arrayN_aligned)(
size_t len,
size_t size,
size_t alignment,
const char *str) /* ATTR_MALLOC */ ATTR_WARN_UNUSED_RESULT ATTR_ALLOC_SIZE(1, 2)
ATTR_NONNULL(4);
/** /**
* Allocate an aligned block of memory that is initialized with zeros. * Allocate an aligned block of memory that is initialized with zeros.
*/ */
@@ -190,11 +200,9 @@ extern size_t (*MEM_get_peak_memory)(void) ATTR_WARN_UNUSED_RESULT;
#ifdef __cplusplus #ifdef __cplusplus
# define MEM_SAFE_FREE(v) \ # define MEM_SAFE_FREE(v) \
do { \ do { \
static_assert(std::is_pointer_v<std::decay_t<decltype(v)>>); \ if (v) { \
void **_v = (void **)&(v); \ MEM_freeN<std::remove_pointer_t<std::decay_t<decltype(v)>>>(v); \
if (*_v) { \ (v) = nullptr; \
MEM_freeN(*_v); \
*_v = NULL; \
} \ } \
} while (0) } while (0)
#else #else
@@ -334,6 +342,18 @@ template<typename T> inline void MEM_delete(const T *ptr)
mem_guarded::internal::AllocationType::NEW_DELETE); mem_guarded::internal::AllocationType::NEW_DELETE);
} }
/**
* Helper shortcut to #MEM_delete, that also ensures that the target pointer is set to nullptr
* after deleting it.
*/
# define MEM_SAFE_DELETE(v) \
do { \
if (v) { \
MEM_delete(v); \
(v) = nullptr; \
} \
} while (0)
/** /**
* Allocate zero-initialized memory for an object of type #T. The constructor of #T is not called, * Allocate zero-initialized memory for an object of type #T. The constructor of #T is not called,
* therefore this should only be used with trivial types (like all C types). * therefore this should only be used with trivial types (like all C types).
@@ -377,6 +397,25 @@ template<typename T> inline T *MEM_cnew(const char *allocation_name, const T &ot
return new_object; return new_object;
} }
template<typename T> inline void MEM_freeN(T *ptr)
{
if constexpr (std::is_void_v<T>) {
mem_guarded::internal::mem_freeN_ex(const_cast<void *>(ptr),
mem_guarded::internal::AllocationType::ALLOC_FREE);
}
else {
# ifndef _WIN32
/* MSVC seems to consider C-style types using the MEM_CXX_CLASS_ALLOC_FUNCS as non-trivial. GCC
* and clang (both on linux and OSX) do not.
*
* So for now, disable the triviality check on Windows. */
static_assert(std::is_trivial_v<T>, "For non-trivial types, MEM_delete must be used.");
# endif
mem_guarded::internal::mem_freeN_ex(const_cast<void *>(static_cast<const void *>(ptr)),
mem_guarded::internal::AllocationType::ALLOC_FREE);
}
}
/** Allocation functions (for C++ only). */ /** Allocation functions (for C++ only). */
# define MEM_CXX_CLASS_ALLOC_FUNCS(_id) \ # define MEM_CXX_CLASS_ALLOC_FUNCS(_id) \
public: \ public: \

View File

@@ -48,6 +48,10 @@ void *(*mem_guarded::internal::mem_mallocN_aligned_ex)(size_t len,
const char *str, const char *str,
AllocationType allocation_type) = AllocationType allocation_type) =
MEM_lockfree_mallocN_aligned; MEM_lockfree_mallocN_aligned;
void *(*MEM_malloc_arrayN_aligned)(size_t len,
size_t size,
size_t alignment,
const char *str) = MEM_lockfree_malloc_arrayN_aligned;
void *(*MEM_calloc_arrayN_aligned)(size_t len, void *(*MEM_calloc_arrayN_aligned)(size_t len,
size_t size, size_t size,
size_t alignment, size_t alignment,
@@ -146,6 +150,7 @@ void MEM_use_lockfree_allocator()
MEM_mallocN = MEM_lockfree_mallocN; MEM_mallocN = MEM_lockfree_mallocN;
MEM_malloc_arrayN = MEM_lockfree_malloc_arrayN; MEM_malloc_arrayN = MEM_lockfree_malloc_arrayN;
mem_mallocN_aligned_ex = MEM_lockfree_mallocN_aligned; mem_mallocN_aligned_ex = MEM_lockfree_mallocN_aligned;
MEM_malloc_arrayN_aligned = MEM_lockfree_malloc_arrayN_aligned;
MEM_calloc_arrayN_aligned = MEM_lockfree_calloc_arrayN_aligned; MEM_calloc_arrayN_aligned = MEM_lockfree_calloc_arrayN_aligned;
MEM_printmemlist_pydict = MEM_lockfree_printmemlist_pydict; MEM_printmemlist_pydict = MEM_lockfree_printmemlist_pydict;
MEM_printmemlist = MEM_lockfree_printmemlist; MEM_printmemlist = MEM_lockfree_printmemlist;
@@ -181,6 +186,7 @@ void MEM_use_guarded_allocator()
MEM_mallocN = MEM_guarded_mallocN; MEM_mallocN = MEM_guarded_mallocN;
MEM_malloc_arrayN = MEM_guarded_malloc_arrayN; MEM_malloc_arrayN = MEM_guarded_malloc_arrayN;
mem_mallocN_aligned_ex = MEM_guarded_mallocN_aligned; mem_mallocN_aligned_ex = MEM_guarded_mallocN_aligned;
MEM_malloc_arrayN_aligned = MEM_guarded_malloc_arrayN_aligned;
MEM_calloc_arrayN_aligned = MEM_guarded_calloc_arrayN_aligned; MEM_calloc_arrayN_aligned = MEM_guarded_calloc_arrayN_aligned;
MEM_printmemlist_pydict = MEM_guarded_printmemlist_pydict; MEM_printmemlist_pydict = MEM_guarded_printmemlist_pydict;
MEM_printmemlist = MEM_guarded_printmemlist; MEM_printmemlist = MEM_guarded_printmemlist;

View File

@@ -702,13 +702,13 @@ void *MEM_guarded_calloc_arrayN(size_t len, size_t size, const char *str)
return MEM_guarded_callocN(total_size, str); return MEM_guarded_callocN(total_size, str);
} }
void *MEM_guarded_calloc_arrayN_aligned(const size_t len, static void *mem_guarded_malloc_arrayN_aligned(const size_t len,
const size_t size, const size_t size,
const size_t alignment, const size_t alignment,
const char *str) const char *str,
size_t &r_bytes_num)
{ {
size_t bytes_num; if (UNLIKELY(!MEM_size_safe_multiply(len, size, &r_bytes_num))) {
if (UNLIKELY(!MEM_size_safe_multiply(len, size, &bytes_num))) {
print_error( print_error(
"Calloc array aborted due to integer overflow: " "Calloc array aborted due to integer overflow: "
"len=" SIZET_FORMAT "x" SIZET_FORMAT " in %s, total " SIZET_FORMAT "\n", "len=" SIZET_FORMAT "x" SIZET_FORMAT " in %s, total " SIZET_FORMAT "\n",
@@ -720,11 +720,29 @@ void *MEM_guarded_calloc_arrayN_aligned(const size_t len,
return nullptr; return nullptr;
} }
if (alignment <= MEM_MIN_CPP_ALIGNMENT) { if (alignment <= MEM_MIN_CPP_ALIGNMENT) {
return MEM_callocN(bytes_num, str); return MEM_callocN(r_bytes_num, str);
} }
return MEM_mallocN_aligned(r_bytes_num, alignment, str);
}
void *MEM_guarded_malloc_arrayN_aligned(const size_t len,
const size_t size,
const size_t alignment,
const char *str)
{
size_t bytes_num;
return mem_guarded_malloc_arrayN_aligned(len, size, alignment, str, bytes_num);
}
void *MEM_guarded_calloc_arrayN_aligned(const size_t len,
const size_t size,
const size_t alignment,
const char *str)
{
size_t bytes_num;
/* There is no lower level #calloc with an alignment parameter, so we have to fallback to using /* There is no lower level #calloc with an alignment parameter, so we have to fallback to using
* #memset unfortunately. */ * #memset unfortunately. */
void *ptr = MEM_mallocN_aligned(bytes_num, alignment, str); void *ptr = mem_guarded_malloc_arrayN_aligned(len, size, alignment, str, bytes_num);
if (!ptr) { if (!ptr) {
return nullptr; return nullptr;
} }

View File

@@ -135,6 +135,11 @@ void *MEM_lockfree_mallocN_aligned(size_t len,
const char *str, const char *str,
mem_guarded::internal::AllocationType allocation_type) mem_guarded::internal::AllocationType allocation_type)
ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_ALLOC_SIZE(1) ATTR_NONNULL(3); ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_ALLOC_SIZE(1) ATTR_NONNULL(3);
void *MEM_lockfree_malloc_arrayN_aligned(size_t len,
size_t size,
size_t alignment,
const char *str) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
ATTR_ALLOC_SIZE(1, 2) ATTR_NONNULL(4);
void *MEM_lockfree_calloc_arrayN_aligned(size_t len, void *MEM_lockfree_calloc_arrayN_aligned(size_t len,
size_t size, size_t size,
size_t alignment, size_t alignment,
@@ -188,6 +193,8 @@ void *MEM_guarded_mallocN_aligned(size_t len,
const char *str, const char *str,
mem_guarded::internal::AllocationType allocation_type) mem_guarded::internal::AllocationType allocation_type)
ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_ALLOC_SIZE(1) ATTR_NONNULL(3); ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_ALLOC_SIZE(1) ATTR_NONNULL(3);
void *MEM_guarded_malloc_arrayN_aligned(size_t len, size_t size, size_t alignment, const char *str)
ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_ALLOC_SIZE(1, 2) ATTR_NONNULL(4);
void *MEM_guarded_calloc_arrayN_aligned(size_t len, size_t size, size_t alignment, const char *str) void *MEM_guarded_calloc_arrayN_aligned(size_t len, size_t size, size_t alignment, const char *str)
ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_ALLOC_SIZE(1, 2) ATTR_NONNULL(4); ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_ALLOC_SIZE(1, 2) ATTR_NONNULL(4);
void MEM_guarded_printmemlist_pydict(void); void MEM_guarded_printmemlist_pydict(void);

View File

@@ -456,13 +456,13 @@ void *MEM_lockfree_mallocN_aligned(size_t len,
return nullptr; return nullptr;
} }
void *MEM_lockfree_calloc_arrayN_aligned(const size_t len, static void *mem_lockfree_malloc_arrayN_aligned(const size_t len,
const size_t size, const size_t size,
const size_t alignment, const size_t alignment,
const char *str) const char *str,
size_t &r_bytes_num)
{ {
size_t bytes_num; if (UNLIKELY(!MEM_size_safe_multiply(len, size, &r_bytes_num))) {
if (UNLIKELY(!MEM_size_safe_multiply(len, size, &bytes_num))) {
print_error( print_error(
"Calloc array aborted due to integer overflow: " "Calloc array aborted due to integer overflow: "
"len=" SIZET_FORMAT "x" SIZET_FORMAT " in %s, total " SIZET_FORMAT "\n", "len=" SIZET_FORMAT "x" SIZET_FORMAT " in %s, total " SIZET_FORMAT "\n",
@@ -474,11 +474,30 @@ void *MEM_lockfree_calloc_arrayN_aligned(const size_t len,
return nullptr; return nullptr;
} }
if (alignment <= MEM_MIN_CPP_ALIGNMENT) { if (alignment <= MEM_MIN_CPP_ALIGNMENT) {
return MEM_callocN(bytes_num, str); return MEM_mallocN(r_bytes_num, str);
} }
void *ptr = MEM_mallocN_aligned(r_bytes_num, alignment, str);
return ptr;
}
void *MEM_lockfree_malloc_arrayN_aligned(const size_t len,
const size_t size,
const size_t alignment,
const char *str)
{
size_t bytes_num;
return mem_lockfree_malloc_arrayN_aligned(len, size, alignment, str, bytes_num);
}
void *MEM_lockfree_calloc_arrayN_aligned(const size_t len,
const size_t size,
const size_t alignment,
const char *str)
{
size_t bytes_num;
/* There is no lower level #calloc with an alignment parameter, so we have to fallback to using /* There is no lower level #calloc with an alignment parameter, so we have to fallback to using
* #memset unfortunately. */ * #memset unfortunately. */
void *ptr = MEM_mallocN_aligned(bytes_num, alignment, str); void *ptr = mem_lockfree_malloc_arrayN_aligned(len, size, alignment, str, bytes_num);
if (!ptr) { if (!ptr) {
return nullptr; return nullptr;
} }

View File

@@ -23,13 +23,14 @@
{ \ { \
if (what) { \ if (what) { \
((type*)what)->~type(); \ ((type*)what)->~type(); \
MEM_freeN(what); \ MEM_freeN(const_cast<void*>(static_cast<const void*>(what))); \
} \ } \
} \ } \
(void)0 (void)0
# define LIBMV_STRUCT_NEW(type, count) \ # define LIBMV_STRUCT_NEW(type, count) \
(type*)MEM_mallocN(sizeof(type) * count, __func__) (type*)MEM_mallocN(sizeof(type) * count, __func__)
# define LIBMV_STRUCT_DELETE(what) MEM_freeN(what) # define LIBMV_STRUCT_DELETE(what) \
MEM_freeN(const_cast<void*>(static_cast<const void*>(what)))
#else #else
// Need this to keep libmv-capi potentially standalone. // Need this to keep libmv-capi potentially standalone.
# if defined __GNUC__ || defined __sun # if defined __GNUC__ || defined __sun

View File

@@ -56,7 +56,7 @@ template<typename _Tp> struct MEM_Allocator {
// __p is not permitted to be a null pointer. // __p is not permitted to be a null pointer.
void deallocate(pointer __p, size_type /*unused*/) void deallocate(pointer __p, size_type /*unused*/)
{ {
MEM_freeN(__p); MEM_freeN(static_cast<void *>(__p));
} }
size_type max_size() const noexcept size_type max_size() const noexcept

View File

@@ -526,7 +526,7 @@ OCIO_PackedImageDesc *FallbackImpl::createOCIO_PackedImageDesc(float *data,
void FallbackImpl::OCIO_PackedImageDescRelease(OCIO_PackedImageDesc *id) void FallbackImpl::OCIO_PackedImageDescRelease(OCIO_PackedImageDesc *id)
{ {
MEM_freeN(id); MEM_freeN(reinterpret_cast<OCIO_PackedImageDescription *>(id));
} }
const char *FallbackImpl::getVersionString() const char *FallbackImpl::getVersionString()

View File

@@ -266,7 +266,12 @@ void BKE_view_layer_free_ex(ViewLayer *view_layer, const bool do_id_user)
BLI_freelistN(&view_layer->lightgroups); BLI_freelistN(&view_layer->lightgroups);
view_layer->active_lightgroup = nullptr; view_layer->active_lightgroup = nullptr;
MEM_SAFE_FREE(view_layer->stats); /* Cannot use MEM_SAFE_FREE, as #SceneStats type is only forward-declared in `DNA_layer_types.h`
*/
if (view_layer->stats) {
MEM_freeN(static_cast<void *>(view_layer->stats));
view_layer->stats = nullptr;
}
BKE_freestyle_config_free(&view_layer->freestyle_config, do_id_user); BKE_freestyle_config_free(&view_layer->freestyle_config, do_id_user);

View File

@@ -170,7 +170,7 @@ void BKE_main_destroy(Main &bmain)
BKE_main_clear(bmain); BKE_main_clear(bmain);
BLI_spin_end(reinterpret_cast<SpinLock *>(bmain.lock)); BLI_spin_end(reinterpret_cast<SpinLock *>(bmain.lock));
MEM_freeN(bmain.lock); MEM_freeN(static_cast<void *>(bmain.lock));
bmain.lock = nullptr; bmain.lock = nullptr;
} }

View File

@@ -195,8 +195,7 @@ void BKE_main_namemap_destroy(UniqueName_Map **r_name_map)
printf( printf(
"NameMap memory usage: sets %.1fKB, maps %.1fKB\n", size_sets / 1024.0, size_maps / 1024.0); "NameMap memory usage: sets %.1fKB, maps %.1fKB\n", size_sets / 1024.0, size_maps / 1024.0);
#endif #endif
MEM_delete<UniqueName_Map>(*r_name_map); MEM_SAFE_DELETE(*r_name_map);
*r_name_map = nullptr;
} }
void BKE_main_namemap_clear(Main *bmain) void BKE_main_namemap_clear(Main *bmain)

View File

@@ -1116,7 +1116,7 @@ void multires_modifier_update_mdisps(DerivedMesh *dm, Scene *scene)
} }
/* lower level dm no longer needed at this point */ /* lower level dm no longer needed at this point */
MEM_freeN(diffGrid); MEM_freeN(static_cast<void *>(diffGrid));
lowdm->release(lowdm); lowdm->release(lowdm);
/* subsurf higher levels again with difference of coordinates */ /* subsurf higher levels again with difference of coordinates */
@@ -1130,7 +1130,7 @@ void multires_modifier_update_mdisps(DerivedMesh *dm, Scene *scene)
/* free */ /* free */
highdm->release(highdm); highdm->release(highdm);
for (i = 0; i < numGrids; i++) { for (i = 0; i < numGrids; i++) {
MEM_freeN(subGridData[i]); MEM_freeN(static_cast<void *>(subGridData[i]));
} }
MEM_freeN(subGridData); MEM_freeN(subGridData);
} }
@@ -1282,7 +1282,7 @@ DerivedMesh *multires_make_derived_from_derived(
} }
for (i = 0; i < numGrids; i++) { for (i = 0; i < numGrids; i++) {
MEM_freeN(subGridData[i]); MEM_freeN(static_cast<void *>(subGridData[i]));
} }
MEM_freeN(subGridData); MEM_freeN(subGridData);

View File

@@ -78,7 +78,12 @@ static void screen_free_data(ID *id)
BKE_previewimg_free(&screen->preview); BKE_previewimg_free(&screen->preview);
/* Region and timer are freed by the window manager. */ /* Region and timer are freed by the window manager. */
MEM_SAFE_FREE(screen->tool_tip); /* Cannot use MEM_SAFE_FREE, as #wmTooltipState type is only defined in `WM_types.hh`, which is
* currently not included here. */
if (screen->tool_tip) {
MEM_freeN(static_cast<void *>(screen->tool_tip));
screen->tool_tip = nullptr;
}
} }
void BKE_screen_foreach_id_screen_area(LibraryForeachIDData *data, ScrArea *area) void BKE_screen_foreach_id_screen_area(LibraryForeachIDData *data, ScrArea *area)

View File

@@ -172,14 +172,13 @@ void BLI_bitmap_randomize(BLI_bitmap *bitmap, uint bits_num, uint seed)
/* ********* for threaded random ************** */ /* ********* for threaded random ************** */
struct RNG_THREAD_ARRAY { struct RNG_THREAD_ARRAY {
RNG rng_tab[BLENDER_MAX_THREADS]; std::array<RNG, BLENDER_MAX_THREADS> rng_tab;
}; };
RNG_THREAD_ARRAY *BLI_rng_threaded_new() RNG_THREAD_ARRAY *BLI_rng_threaded_new()
{ {
uint i; uint i;
RNG_THREAD_ARRAY *rngarr = (RNG_THREAD_ARRAY *)MEM_mallocN(sizeof(RNG_THREAD_ARRAY), RNG_THREAD_ARRAY *rngarr = MEM_new<RNG_THREAD_ARRAY>("random_array");
"random_array");
for (i = 0; i < BLENDER_MAX_THREADS; i++) { for (i = 0; i < BLENDER_MAX_THREADS; i++) {
BLI_rng_srandom(&rngarr->rng_tab[i], uint(clock())); BLI_rng_srandom(&rngarr->rng_tab[i], uint(clock()));
@@ -190,12 +189,12 @@ RNG_THREAD_ARRAY *BLI_rng_threaded_new()
void BLI_rng_threaded_free(RNG_THREAD_ARRAY *rngarr) void BLI_rng_threaded_free(RNG_THREAD_ARRAY *rngarr)
{ {
MEM_freeN(rngarr); MEM_delete(rngarr);
} }
int BLI_rng_thread_rand(RNG_THREAD_ARRAY *rngarr, int thread) int BLI_rng_thread_rand(RNG_THREAD_ARRAY *rngarr, int thread)
{ {
return BLI_rng_get_int(&rngarr->rng_tab[thread]); return BLI_rng_get_int(&rngarr->rng_tab[size_t(thread)]);
} }
/* ********* Low-discrepancy sequences ************** */ /* ********* Low-discrepancy sequences ************** */

View File

@@ -68,7 +68,7 @@ struct TimeSourceNode;
class DepsgraphNodeBuilder : public DepsgraphBuilder { class DepsgraphNodeBuilder : public DepsgraphBuilder {
public: public:
DepsgraphNodeBuilder(Main *bmain, Depsgraph *graph, DepsgraphBuilderCache *cache); DepsgraphNodeBuilder(Main *bmain, Depsgraph *graph, DepsgraphBuilderCache *cache);
~DepsgraphNodeBuilder() override; ~DepsgraphNodeBuilder();
/* For given original ID get ID which is created by copy-on-evaluation system. */ /* For given original ID get ID which is created by copy-on-evaluation system. */
ID *get_cow_id(const ID *id_orig) const; ID *get_cow_id(const ID *id_orig) const;

View File

@@ -290,7 +290,7 @@ class UniformArrayBuffer : public detail::UniformCommon<T, len, false> {
} }
~UniformArrayBuffer() ~UniformArrayBuffer()
{ {
MEM_freeN(this->data_); MEM_freeN(static_cast<void *>(this->data_));
} }
}; };
@@ -337,7 +337,9 @@ class StorageArrayBuffer : public detail::StorageCommon<T, len, device_only> {
} }
~StorageArrayBuffer() ~StorageArrayBuffer()
{ {
MEM_freeN(this->data_); /* NOTE: T is not always trivial (e.g. can be #blender::eevee::VelocityIndex), so cannot use
* `MEM_freeN` directly on it, without casting it to `void *`. */
MEM_freeN(static_cast<void *>(this->data_));
} }
/* Resize to \a new_size elements. */ /* Resize to \a new_size elements. */
@@ -348,7 +350,7 @@ class StorageArrayBuffer : public detail::StorageCommon<T, len, device_only> {
/* Manual realloc since MEM_reallocN_aligned does not exists. */ /* Manual realloc since MEM_reallocN_aligned does not exists. */
T *new_data_ = (T *)MEM_mallocN_aligned(new_size * sizeof(T), 16, this->name_); T *new_data_ = (T *)MEM_mallocN_aligned(new_size * sizeof(T), 16, this->name_);
memcpy(new_data_, this->data_, min_uu(this->len_, new_size) * sizeof(T)); memcpy(new_data_, this->data_, min_uu(this->len_, new_size) * sizeof(T));
MEM_freeN(this->data_); MEM_freeN(static_cast<void *>(this->data_));
this->data_ = new_data_; this->data_ = new_data_;
GPU_storagebuf_free(this->ssbo_); GPU_storagebuf_free(this->ssbo_);

View File

@@ -57,7 +57,7 @@ class FileListWrapper {
static void filelist_free_fn(FileList *list) static void filelist_free_fn(FileList *list)
{ {
filelist_free(list); filelist_free(list);
MEM_freeN(list); MEM_freeN(static_cast<void *>(list));
} }
std::unique_ptr<FileList, decltype(&filelist_free_fn)> file_list_; std::unique_ptr<FileList, decltype(&filelist_free_fn)> file_list_;

View File

@@ -1290,7 +1290,11 @@ static void gizmo_cage2d_exit(bContext *C, wmGizmo *gz, const bool cancel)
{ {
RectTransformInteraction *data = static_cast<RectTransformInteraction *>(gz->interaction_data); RectTransformInteraction *data = static_cast<RectTransformInteraction *>(gz->interaction_data);
MEM_SAFE_FREE(data->dial); /* Cannot use MEM_SAFE_FREE, as #Dial type is only forward-declared in `BLI_dial_2d.h` */
if (data->dial) {
MEM_freeN(static_cast<void *>(data->dial));
data->dial = nullptr;
}
if (!cancel) { if (!cancel) {
return; return;

View File

@@ -1073,7 +1073,7 @@ static void annotation_free_stroke(bGPDframe *gpf, bGPDstroke *gps)
if (gps->dvert) { if (gps->dvert) {
BKE_gpencil_free_stroke_weights(gps); BKE_gpencil_free_stroke_weights(gps);
MEM_freeN(gps->dvert); MEM_freeN(static_cast<void *>(gps->dvert));
} }
if (gps->triangles) { if (gps->triangles) {

View File

@@ -71,7 +71,7 @@ void region_reset(ARegion &region, const RegionViewData &data)
region.winrct = data.winrct; region.winrct = data.winrct;
ED_view3d_mats_rv3d_restore(&rv3d, data.rv3d_store); ED_view3d_mats_rv3d_restore(&rv3d, data.rv3d_store);
MEM_freeN(data.rv3d_store); MEM_freeN(static_cast<void *>(data.rv3d_store));
} }
GPUOffScreen *image_render_begin(const int2 &win_size) GPUOffScreen *image_render_begin(const int2 &win_size)

View File

@@ -3905,7 +3905,11 @@ namespace blender::ed::sculpt_paint {
StrokeCache::~StrokeCache() StrokeCache::~StrokeCache()
{ {
MEM_SAFE_FREE(this->dial); /* Cannot use MEM_SAFE_FREE, as #Dial type is only forward-declared in `BLI_dial_2d.h` */
if (this->dial) {
MEM_freeN(static_cast<void *>(this->dial));
this->dial = nullptr;
}
} }
} // namespace blender::ed::sculpt_paint } // namespace blender::ed::sculpt_paint

View File

@@ -1329,7 +1329,7 @@ void ED_fileselect_exit(wmWindowManager *wm, SpaceFile *sfile)
if (sfile->files) { if (sfile->files) {
ED_fileselect_clear(wm, sfile); ED_fileselect_clear(wm, sfile);
filelist_free(sfile->files); filelist_free(sfile->files);
MEM_freeN(sfile->files); MEM_freeN(static_cast<void *>(sfile->files));
sfile->files = nullptr; sfile->files = nullptr;
} }
} }

View File

@@ -117,7 +117,7 @@ static void file_free(SpaceLink *sl)
/* XXX would need to do thumbnails_stop here, but no context available */ /* XXX would need to do thumbnails_stop here, but no context available */
filelist_freelib(sfile->files); filelist_freelib(sfile->files);
filelist_free(sfile->files); filelist_free(sfile->files);
MEM_freeN(sfile->files); MEM_freeN(static_cast<void *>(sfile->files));
sfile->files = nullptr; sfile->files = nullptr;
} }

View File

@@ -277,7 +277,12 @@ static void view3d_free(SpaceLink *sl)
MEM_freeN(vd->localvd); MEM_freeN(vd->localvd);
} }
MEM_SAFE_FREE(vd->runtime.local_stats); /* Cannot use MEM_SAFE_FREE, as #SceneStats type is only forward-declared in `DNA_layer_types.h`
*/
if (vd->runtime.local_stats) {
MEM_freeN(static_cast<void *>(vd->runtime.local_stats));
vd->runtime.local_stats = nullptr;
}
if (vd->runtime.properties_storage_free) { if (vd->runtime.properties_storage_free) {
vd->runtime.properties_storage_free(vd->runtime.properties_storage); vd->runtime.properties_storage_free(vd->runtime.properties_storage);
@@ -299,7 +304,12 @@ static void view3d_exit(wmWindowManager * /*wm*/, ScrArea *area)
{ {
BLI_assert(area->spacetype == SPACE_VIEW3D); BLI_assert(area->spacetype == SPACE_VIEW3D);
View3D *v3d = static_cast<View3D *>(area->spacedata.first); View3D *v3d = static_cast<View3D *>(area->spacedata.first);
MEM_SAFE_FREE(v3d->runtime.local_stats); /* Cannot use MEM_SAFE_FREE, as #SceneStats type is only forward-declared in `DNA_layer_types.h`
*/
if (v3d->runtime.local_stats) {
MEM_freeN(static_cast<void *>(v3d->runtime.local_stats));
v3d->runtime.local_stats = nullptr;
}
} }
static SpaceLink *view3d_duplicate(SpaceLink *sl) static SpaceLink *view3d_duplicate(SpaceLink *sl)
@@ -1048,7 +1058,7 @@ static void view3d_main_region_free(ARegion *region)
} }
if (rv3d->sms) { if (rv3d->sms) {
MEM_freeN(rv3d->sms); MEM_freeN(static_cast<void *>(rv3d->sms));
} }
MEM_freeN(rv3d); MEM_freeN(rv3d);
@@ -2006,7 +2016,12 @@ static void space_view3d_listener(const wmSpaceTypeListenerParams *params)
static void space_view3d_refresh(const bContext *C, ScrArea *area) static void space_view3d_refresh(const bContext *C, ScrArea *area)
{ {
View3D *v3d = (View3D *)area->spacedata.first; View3D *v3d = (View3D *)area->spacedata.first;
MEM_SAFE_FREE(v3d->runtime.local_stats); /* Cannot use MEM_SAFE_FREE, as #SceneStats type is only forward-declared in `DNA_layer_types.h`
*/
if (v3d->runtime.local_stats) {
MEM_freeN(static_cast<void *>(v3d->runtime.local_stats));
v3d->runtime.local_stats = nullptr;
}
if (v3d->localvd && v3d->localvd->runtime.flag & V3D_RUNTIME_LOCAL_MAYBE_EMPTY) { if (v3d->localvd && v3d->localvd->runtime.flag & V3D_RUNTIME_LOCAL_MAYBE_EMPTY) {
ED_localview_exit_if_empty(CTX_data_ensure_evaluated_depsgraph(C), ED_localview_exit_if_empty(CTX_data_ensure_evaluated_depsgraph(C),

View File

@@ -385,7 +385,11 @@ void ViewOpsData::end_navigation(bContext *C)
WM_event_timer_remove(CTX_wm_manager(C), this->timer->win, this->timer); WM_event_timer_remove(CTX_wm_manager(C), this->timer->win, this->timer);
} }
MEM_SAFE_FREE(this->init.dial); /* Cannot use MEM_SAFE_FREE, as #Dial type is only forward-declared in `BLI_dial_2d.h` */
if (this->init.dial) {
MEM_freeN(static_cast<void *>(this->init.dial));
this->init.dial = nullptr;
}
/* Need to redraw because drawing code uses RV3D_NAVIGATING to draw /* Need to redraw because drawing code uses RV3D_NAVIGATING to draw
* faster while navigation operator runs. */ * faster while navigation operator runs. */

View File

@@ -985,7 +985,12 @@ static bool view3d_localview_exit(const Depsgraph *depsgraph,
MEM_freeN(v3d->localvd); MEM_freeN(v3d->localvd);
v3d->localvd = nullptr; v3d->localvd = nullptr;
MEM_SAFE_FREE(v3d->runtime.local_stats); /* Cannot use MEM_SAFE_FREE, as #SceneStats type is only forward-declared in `DNA_layer_types.h`
*/
if (v3d->runtime.local_stats) {
MEM_freeN(static_cast<void *>(v3d->runtime.local_stats));
v3d->runtime.local_stats = nullptr;
}
LISTBASE_FOREACH (ARegion *, region, &area->regionbase) { LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
if (region->regiontype == RGN_TYPE_WINDOW) { if (region->regiontype == RGN_TYPE_WINDOW) {

View File

@@ -3507,7 +3507,7 @@ static int uv_from_view_exec(bContext *C, wmOperator *op)
changed = true; changed = true;
} }
MEM_freeN(uci); MEM_freeN(static_cast<void *>(uci));
} }
} }
else { else {

View File

@@ -269,7 +269,8 @@ static void rna_Main_materials_gpencil_remove(Main * /*bmain*/, PointerRNA *id_p
ID *id = static_cast<ID *>(id_ptr->data); ID *id = static_cast<ID *>(id_ptr->data);
Material *ma = (Material *)id; Material *ma = (Material *)id;
if (ma->gp_style) { if (ma->gp_style) {
MEM_SAFE_FREE(ma->gp_style); MEM_freeN(ma->gp_style);
ma->gp_style = nullptr;
} }
} }

View File

@@ -159,7 +159,7 @@ void WM_gizmo_free(wmGizmo *gz)
/* Explicit calling of the destructor is needed here because allocation still happens 'the C /* Explicit calling of the destructor is needed here because allocation still happens 'the C
* way', see FIXME note in #wm_gizmo_create. */ * way', see FIXME note in #wm_gizmo_create. */
gz->~wmGizmo(); gz->~wmGizmo();
MEM_freeN(gz); MEM_freeN(static_cast<void *>(gz));
} }
void WM_gizmo_unlink(ListBase *gizmolist, wmGizmoMap *gzmap, wmGizmo *gz, bContext *C) void WM_gizmo_unlink(ListBase *gizmolist, wmGizmoMap *gzmap, wmGizmo *gz, bContext *C)

View File

@@ -3208,7 +3208,11 @@ static void radial_control_cancel(bContext *C, wmOperator *op)
wmWindowManager *wm = CTX_wm_manager(C); wmWindowManager *wm = CTX_wm_manager(C);
ScrArea *area = CTX_wm_area(C); ScrArea *area = CTX_wm_area(C);
MEM_SAFE_FREE(rc->dial); /* Cannot use MEM_SAFE_FREE, as #Dial type is only forward-declared in `BLI_dial_2d.h` */
if (rc->dial) {
MEM_freeN(static_cast<void *>(rc->dial));
rc->dial = nullptr;
}
ED_area_status_text(area, nullptr); ED_area_status_text(area, nullptr);
@@ -3401,7 +3405,11 @@ static int radial_control_modal(bContext *C, wmOperator *op, const wmEvent *even
if (event->val == KM_RELEASE) { if (event->val == KM_RELEASE) {
rc->slow_mode = false; rc->slow_mode = false;
handled = true; handled = true;
MEM_SAFE_FREE(rc->dial); /* Cannot use MEM_SAFE_FREE, as #Dial type is only forward-declared in `BLI_dial_2d.h` */
if (rc->dial) {
MEM_freeN(static_cast<void *>(rc->dial));
rc->dial = nullptr;
}
} }
break; break;
} }