MEM: support overaligned types in MEM_cnew_array

This is similar to the recent change for `MEM_cnew`: 60a3d85b88.
A new function called `MEM_calloc_arrayN_aligned` is added that is used by both `cnew` functions now.

Pull Request: https://projects.blender.org/blender/blender/pulls/120632
This commit is contained in:
Jacques Lucke
2024-04-15 19:11:06 +02:00
parent 0a7510ebaa
commit 00648411ea
5 changed files with 86 additions and 9 deletions

View File

@@ -134,6 +134,16 @@ extern void *(*MEM_mallocN_aligned)(size_t len,
const char *str) /* ATTR_MALLOC */ ATTR_WARN_UNUSED_RESULT
ATTR_ALLOC_SIZE(1) ATTR_NONNULL(3);
/**
* Allocate an aligned block of memory that is initialized with zeros.
*/
extern void *(*MEM_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);
/**
* Print a list of the names and sizes of all allocated memory
* blocks. as a python dict for easy investigation.
@@ -311,14 +321,7 @@ template<typename T> inline void MEM_delete(const T *ptr)
template<typename T> inline T *MEM_cnew(const char *allocation_name)
{
static_assert(std::is_trivial_v<T>, "For non-trivial types, MEM_new should be used.");
if (alignof(T) <= MEM_MIN_CPP_ALIGNMENT) {
return static_cast<T *>(MEM_callocN(sizeof(T), allocation_name));
}
void *ptr = MEM_mallocN_aligned(sizeof(T), alignof(T), allocation_name);
if (ptr) {
memset(ptr, 0, sizeof(T));
}
return static_cast<T *>(ptr);
return static_cast<T *>(MEM_calloc_arrayN_aligned(1, sizeof(T), alignof(T), allocation_name));
}
/**
@@ -327,7 +330,8 @@ template<typename T> inline T *MEM_cnew(const char *allocation_name)
template<typename T> inline T *MEM_cnew_array(const size_t length, const char *allocation_name)
{
static_assert(std::is_trivial_v<T>, "For non-trivial types, MEM_new should be used.");
return static_cast<T *>(MEM_calloc_arrayN(length, sizeof(T), allocation_name));
return static_cast<T *>(
MEM_calloc_arrayN_aligned(length, sizeof(T), alignof(T), allocation_name));
}
/**

View File

@@ -38,6 +38,10 @@ void *(*MEM_malloc_arrayN)(size_t len, size_t size, const char *str) = MEM_lockf
void *(*MEM_mallocN_aligned)(size_t len,
size_t alignment,
const char *str) = MEM_lockfree_mallocN_aligned;
void *(*MEM_calloc_arrayN_aligned)(size_t len,
size_t size,
size_t alignment,
const char *str) = MEM_lockfree_calloc_arrayN_aligned;
void (*MEM_printmemlist_pydict)(void) = MEM_lockfree_printmemlist_pydict;
void (*MEM_printmemlist)(void) = MEM_lockfree_printmemlist;
void (*MEM_callbackmemlist)(void (*func)(void *)) = MEM_lockfree_callbackmemlist;
@@ -120,6 +124,7 @@ void MEM_use_lockfree_allocator(void)
MEM_mallocN = MEM_lockfree_mallocN;
MEM_malloc_arrayN = MEM_lockfree_malloc_arrayN;
MEM_mallocN_aligned = MEM_lockfree_mallocN_aligned;
MEM_calloc_arrayN_aligned = MEM_lockfree_calloc_arrayN_aligned;
MEM_printmemlist_pydict = MEM_lockfree_printmemlist_pydict;
MEM_printmemlist = MEM_lockfree_printmemlist;
MEM_callbackmemlist = MEM_lockfree_callbackmemlist;
@@ -154,6 +159,7 @@ void MEM_use_guarded_allocator(void)
MEM_mallocN = MEM_guarded_mallocN;
MEM_malloc_arrayN = MEM_guarded_malloc_arrayN;
MEM_mallocN_aligned = MEM_guarded_mallocN_aligned;
MEM_calloc_arrayN_aligned = MEM_guarded_calloc_arrayN_aligned;
MEM_printmemlist_pydict = MEM_guarded_printmemlist_pydict;
MEM_printmemlist = MEM_guarded_printmemlist;
MEM_callbackmemlist = MEM_guarded_callbackmemlist;

View File

@@ -619,6 +619,36 @@ void *MEM_guarded_calloc_arrayN(size_t len, size_t size, const char *str)
return MEM_guarded_callocN(total_size, str);
}
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;
if (UNLIKELY(!MEM_size_safe_multiply(len, size, &bytes_num))) {
print_error(
"Calloc array aborted due to integer overflow: "
"len=" SIZET_FORMAT "x" SIZET_FORMAT " in %s, total " SIZET_FORMAT "\n",
SIZET_ARG(len),
SIZET_ARG(size),
str,
mem_in_use);
abort();
return nullptr;
}
if (alignment <= MEM_MIN_CPP_ALIGNMENT) {
return MEM_callocN(bytes_num, str);
}
/* There is no lower level #calloc with an alignment parameter, so we have to fallback to using
* #memset unfortunately. */
void *ptr = MEM_mallocN_aligned(bytes_num, alignment, str);
if (!ptr) {
return nullptr;
}
memset(ptr, 0, bytes_num);
return ptr;
}
/* Memory statistics print */
typedef struct MemPrintBlock {
const char *name;

View File

@@ -155,6 +155,11 @@ void *MEM_lockfree_mallocN_aligned(size_t len,
size_t alignment,
const char *str) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
ATTR_ALLOC_SIZE(1) ATTR_NONNULL(3);
void *MEM_lockfree_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);
void MEM_lockfree_printmemlist_pydict(void);
void MEM_lockfree_printmemlist(void);
void MEM_lockfree_callbackmemlist(void (*func)(void *));
@@ -202,6 +207,8 @@ void *MEM_guarded_mallocN_aligned(size_t len,
size_t alignment,
const char *str) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
ATTR_ALLOC_SIZE(1) ATTR_NONNULL(3);
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);
void MEM_guarded_printmemlist_pydict(void);
void MEM_guarded_printmemlist(void);
void MEM_guarded_callbackmemlist(void (*func)(void *));

View File

@@ -371,6 +371,36 @@ void *MEM_lockfree_mallocN_aligned(size_t len, size_t alignment, const char *str
return nullptr;
}
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;
if (UNLIKELY(!MEM_size_safe_multiply(len, size, &bytes_num))) {
print_error(
"Calloc array aborted due to integer overflow: "
"len=" SIZET_FORMAT "x" SIZET_FORMAT " in %s, total " SIZET_FORMAT "\n",
SIZET_ARG(len),
SIZET_ARG(size),
str,
memory_usage_current());
abort();
return nullptr;
}
if (alignment <= MEM_MIN_CPP_ALIGNMENT) {
return MEM_callocN(bytes_num, str);
}
/* There is no lower level #calloc with an alignment parameter, so we have to fallback to using
* #memset unfortunately. */
void *ptr = MEM_mallocN_aligned(bytes_num, alignment, str);
if (!ptr) {
return nullptr;
}
memset(ptr, 0, bytes_num);
return ptr;
}
void MEM_lockfree_printmemlist_pydict() {}
void MEM_lockfree_printmemlist() {}