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

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