Cleanup: python: Replace 'void' MEM_[cm]allocN with templated, type-safe MEM_[cm]allocN<T>.

The main issue of 'type-less' standard C allocations is that there is no check on
allocated type possible.

This is a serious source of annoyance (and crashes) when making some
low-level structs non-trivial, as tracking down all usages of these
structs in higher-level other structs and their allocation is... really
painful.

MEM_[cm]allocN<T> templates on the other hand do check that the
given type is trivial, at build time (static assert), which makes such issue...
trivial to catch.

NOTE: New code should strive to use MEM_new (i.e. allocation and
construction) as much as possible, even for trivial PoD types.

Pull Request: https://projects.blender.org/blender/blender/pulls/135852
This commit is contained in:
Bastien Montagne 2025-03-12 11:21:53 +01:00 committed by Bastien Montagne
parent 9f697c7cc6
commit bb89c89e7f
13 changed files with 45 additions and 59 deletions

View File

@ -692,8 +692,7 @@ static Buffer *BGL_MakeBuffer_FromData(
Py_XINCREF(parent);
buffer->parent = parent;
buffer->ndimensions = ndimensions;
buffer->dimensions = static_cast<int *>(
MEM_mallocN(ndimensions * sizeof(int), "Buffer dimensions"));
buffer->dimensions = MEM_malloc_arrayN<int>(size_t(ndimensions), "Buffer dimensions");
memcpy(buffer->dimensions, dimensions, ndimensions * sizeof(int));
buffer->type = type;
buffer->buf.asvoid = buf;

View File

@ -2442,7 +2442,7 @@ static int BPy_IDArray_getbuffer(BPy_IDArray *self, Py_buffer *view, int flags)
view->itemsize = itemsize;
view->format = (char *)idp_format_from_array_type(prop->subtype);
Py_ssize_t *shape = static_cast<Py_ssize_t *>(MEM_mallocN(sizeof(Py_ssize_t), __func__));
Py_ssize_t *shape = MEM_mallocN<Py_ssize_t>(__func__);
shape[0] = prop->len;
view->shape = shape;

View File

@ -178,7 +178,7 @@ static bool idprop_ui_data_update_int_default(IDProperty *idprop,
}
Py_ssize_t len = PySequence_Size(default_value);
int *new_default_array = (int *)MEM_malloc_arrayN(len, sizeof(int), __func__);
int *new_default_array = MEM_malloc_arrayN<int>(size_t(len), __func__);
if (PyC_AsArray(
new_default_array, sizeof(int), default_value, len, &PyLong_Type, "ui_data_update") ==
-1)
@ -338,7 +338,7 @@ static bool idprop_ui_data_update_bool_default(IDProperty *idprop,
}
Py_ssize_t len = PySequence_Size(default_value);
int8_t *new_default_array = (int8_t *)MEM_malloc_arrayN(len, sizeof(int8_t), __func__);
int8_t *new_default_array = MEM_malloc_arrayN<int8_t>(size_t(len), __func__);
if (PyC_AsArray(new_default_array,
sizeof(int8_t),
default_value,
@ -428,7 +428,7 @@ static bool idprop_ui_data_update_float_default(IDProperty *idprop,
}
Py_ssize_t len = PySequence_Size(default_value);
double *new_default_array = (double *)MEM_malloc_arrayN(len, sizeof(double), __func__);
double *new_default_array = MEM_malloc_arrayN<double>(size_t(len), __func__);
if (PyC_AsArray(new_default_array,
sizeof(double),
default_value,

View File

@ -1614,8 +1614,8 @@ bool PyC_RunString_AsStringAndSize(const char *imports[],
ok = false;
}
else {
char *val_alloc = static_cast<char *>(MEM_mallocN(val_len + 1, __func__));
memcpy(val_alloc, val, val_len + 1);
char *val_alloc = MEM_malloc_arrayN<char>(size_t(val_len) + 1, __func__);
memcpy(val_alloc, val, (size_t(val_len) + 1) * sizeof(*val_alloc));
*r_value = val_alloc;
*r_value_size = val_len;
ok = true;
@ -1658,8 +1658,8 @@ bool PyC_RunString_AsStringAndSizeOrNone(const char *imports[],
ok = false;
}
else {
char *val_alloc = static_cast<char *>(MEM_mallocN(val_len + 1, __func__));
memcpy(val_alloc, val, val_len + 1);
char *val_alloc = MEM_malloc_arrayN<char>(size_t(val_len) + 1, __func__);
memcpy(val_alloc, val, (size_t(val_len) + 1) * sizeof(val_alloc));
*r_value = val_alloc;
*r_value_size = val_len;
ok = true;

View File

@ -151,9 +151,8 @@ static BPyGPUBuffer *pygpu_buffer_make_from_data(PyObject *parent,
buffer->parent = nullptr;
buffer->format = format;
buffer->shape_len = shape_len;
buffer->shape = static_cast<Py_ssize_t *>(
MEM_mallocN(shape_len * sizeof(*buffer->shape), "BPyGPUBuffer shape"));
memcpy(buffer->shape, shape, shape_len * sizeof(*buffer->shape));
buffer->shape = MEM_malloc_arrayN<Py_ssize_t>(size_t(shape_len), "BPyGPUBuffer shape");
memcpy(buffer->shape, shape, sizeof(*buffer->shape) * size_t(shape_len));
buffer->buf.as_void = buf;
if (parent) {
@ -265,14 +264,13 @@ static int pygpu_buffer_dimensions_set(BPyGPUBuffer *self, PyObject *value, void
return -1;
}
size_t size = shape_len * sizeof(*self->shape);
if (shape_len != self->shape_len) {
MEM_freeN(self->shape);
self->shape = static_cast<Py_ssize_t *>(MEM_mallocN(size, __func__));
self->shape = MEM_malloc_arrayN<Py_ssize_t>(size_t(shape_len), __func__);
}
self->shape_len = shape_len;
memcpy(self->shape, shape, size);
memcpy(self->shape, shape, sizeof(*self->shape) * size_t(shape_len));
return 0;
}
@ -638,8 +636,7 @@ static int pygpu_buffer__bf_getbuffer(BPyGPUBuffer *self, Py_buffer *view, int f
view->shape = self->shape;
}
if (flags & PyBUF_STRIDES) {
view->strides = static_cast<Py_ssize_t *>(
MEM_mallocN(view->ndim * sizeof(*view->strides), "BPyGPUBuffer strides"));
view->strides = MEM_malloc_arrayN<Py_ssize_t>(size_t(view->ndim), "BPyGPUBuffer strides");
pygpu_buffer_strides_calc(
eGPUDataFormat(self->format), view->ndim, view->shape, view->strides);
}

View File

@ -68,15 +68,14 @@ static PyObject *bpy_app_icons_new_triangles(PyObject * /*self*/, PyObject *args
return nullptr;
}
const int coords_size = sizeof(uchar[2]) * tris_len * 3;
const int colors_size = sizeof(uchar[4]) * tris_len * 3;
uchar(*coords)[2] = static_cast<uchar(*)[2]>(MEM_mallocN(coords_size, __func__));
uchar(*colors)[4] = static_cast<uchar(*)[4]>(MEM_mallocN(colors_size, __func__));
const size_t items_num = size_t(tris_len) * 3;
uchar(*coords)[2] = MEM_malloc_arrayN<uchar[2]>(items_num, __func__);
uchar(*colors)[4] = MEM_malloc_arrayN<uchar[4]>(items_num, __func__);
memcpy(coords, PyBytes_AS_STRING(py_coords), coords_size);
memcpy(colors, PyBytes_AS_STRING(py_colors), colors_size);
memcpy(coords, PyBytes_AS_STRING(py_coords), sizeof(*coords) * items_num);
memcpy(colors, PyBytes_AS_STRING(py_colors), sizeof(*colors) * items_num);
Icon_Geom *geom = static_cast<Icon_Geom *>(MEM_mallocN(sizeof(*geom), __func__));
Icon_Geom *geom = MEM_mallocN<Icon_Geom>(__func__);
geom->coords_len = tris_len;
geom->coords_range[0] = coords_range[0];
geom->coords_range[1] = coords_range[1];

View File

@ -229,7 +229,7 @@ static PyObject *pyop_call(PyObject * /*self*/, PyObject *args)
if (error_val == 0) {
ReportList *reports;
reports = static_cast<ReportList *>(MEM_mallocN(sizeof(ReportList), "wmOperatorReportList"));
reports = MEM_mallocN<ReportList>("wmOperatorReportList");
/* Own so these don't move into global reports. */
BKE_reports_init(reports, RPT_STORE | RPT_OP_HOLD | RPT_PRINT_HANDLED_BY_OWNER);

View File

@ -174,7 +174,7 @@ static BPyPropStore *bpy_prop_py_data_ensure(PropertyRNA *prop)
{
BPyPropStore *prop_store = static_cast<BPyPropStore *>(RNA_property_py_data_get(prop));
if (prop_store == nullptr) {
prop_store = static_cast<BPyPropStore *>(MEM_callocN(sizeof(*prop_store), __func__));
prop_store = MEM_callocN<BPyPropStore>(__func__);
RNA_def_py_data(prop, prop_store);
BLI_addtail(&g_bpy_prop_store_list, prop_store);
}
@ -1763,8 +1763,7 @@ static const EnumPropertyItem *enum_items_from_py(PyObject *seq_fast,
/* blank value */
*r_default_value = 0;
items = static_cast<EnumPropertyItem *>(
MEM_callocN(sizeof(EnumPropertyItem) * (seq_len + 1), "enum_items_from_py1"));
items = MEM_calloc_arrayN<EnumPropertyItem>(size_t(seq_len) + 1, "enum_items_from_py1");
for (i = 0; i < seq_len; i++) {
EnumPropertyItem tmp = {0, "", 0, "", ""};

View File

@ -399,7 +399,7 @@ static PyObject *bpy_gizmo_target_set_handler(PyObject * /*self*/, PyObject *arg
}
}
data = static_cast<BPyGizmoHandlerUserData *>(MEM_callocN(sizeof(*data), __func__));
data = MEM_callocN<BPyGizmoHandlerUserData>(__func__);
for (int i = 0; i < BPY_GIZMO_FN_SLOT_LEN; i++) {
data->fn_slots[i] = params.py_fn_slots[i];

View File

@ -694,7 +694,7 @@ static PyObject *C_BVHTree_FromPolygons(PyObject * /*cls*/, PyObject *args, PyOb
if (valid) {
PyObject **py_coords_fast_items = PySequence_Fast_ITEMS(py_coords_fast);
coords_len = uint(PySequence_Fast_GET_SIZE(py_coords_fast));
coords = static_cast<float(*)[3]>(MEM_mallocN(size_t(coords_len) * sizeof(*coords), __func__));
coords = MEM_malloc_arrayN<float[3]>(size_t(coords_len), __func__);
for (i = 0; i < coords_len; i++) {
PyObject *py_vert = py_coords_fast_items[i];
@ -713,7 +713,7 @@ static PyObject *C_BVHTree_FromPolygons(PyObject * /*cls*/, PyObject *args, PyOb
/* all triangles, simple case */
PyObject **py_tris_fast_items = PySequence_Fast_ITEMS(py_tris_fast);
tris_len = uint(PySequence_Fast_GET_SIZE(py_tris_fast));
tris = static_cast<uint(*)[3]>(MEM_mallocN(size_t(tris_len) * sizeof(*tris), __func__));
tris = MEM_malloc_arrayN<uint[3]>(size_t(tris_len), __func__);
for (i = 0; i < tris_len; i++) {
PyObject *py_tricoords = py_tris_fast_items[i];
@ -819,11 +819,10 @@ static PyObject *C_BVHTree_FromPolygons(PyObject * /*cls*/, PyObject *args, PyOb
/* All NGON's are parsed, now tessellate. */
pf_arena = BLI_memarena_new(BLI_POLYFILL_ARENA_SIZE, __func__);
tris = static_cast<uint(*)[3]>(MEM_mallocN(sizeof(*tris) * size_t(tris_len), __func__));
tris = MEM_malloc_arrayN<uint[3]>(size_t(tris_len), __func__);
orig_index = static_cast<int *>(MEM_mallocN(sizeof(*orig_index) * size_t(tris_len), __func__));
orig_normal = static_cast<float(*)[3]>(
MEM_mallocN(sizeof(*orig_normal) * size_t(polys_len), __func__));
orig_index = MEM_malloc_arrayN<int>(size_t(tris_len), __func__);
orig_normal = MEM_malloc_arrayN<float[3]>(size_t(polys_len), __func__);
for (plink = plink_first, poly_index = 0, i = 0; plink; plink = plink->next, poly_index++) {
if (plink->len == 3) {
@ -966,8 +965,8 @@ static PyObject *C_BVHTree_FromBMesh(PyObject * /*cls*/, PyObject *args, PyObjec
coords_len = uint(bm->totvert);
tris_len = uint(poly_to_tri_count(bm->totface, bm->totloop));
coords = static_cast<float(*)[3]>(MEM_mallocN(sizeof(*coords) * size_t(coords_len), __func__));
tris = static_cast<uint(*)[3]>(MEM_mallocN(sizeof(*tris) * size_t(tris_len), __func__));
coords = MEM_malloc_arrayN<float[3]>(size_t(coords_len), __func__);
tris = MEM_malloc_arrayN<uint[3]>(size_t(tris_len), __func__);
blender::Array<std::array<BMLoop *, 3>> corner_tris(tris_len);
BM_mesh_calc_tessellation(bm, corner_tris);
@ -985,10 +984,8 @@ static PyObject *C_BVHTree_FromBMesh(PyObject * /*cls*/, PyObject *args, PyObjec
BMFace *f;
BMVert *v;
orig_index = static_cast<int *>(
MEM_mallocN(sizeof(*orig_index) * size_t(tris_len), __func__));
orig_normal = static_cast<float(*)[3]>(
MEM_mallocN(sizeof(*orig_normal) * size_t(bm->totface), __func__));
orig_index = MEM_malloc_arrayN<int>(size_t(tris_len), __func__);
orig_normal = MEM_malloc_arrayN<float[3]>(size_t(bm->totface), __func__);
BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) {
copy_v3_v3(coords[i], v->co);
@ -1191,10 +1188,8 @@ static PyObject *C_BVHTree_FromObject(PyObject * /*cls*/, PyObject *args, PyObje
const uint coords_len = uint(mesh->verts_num);
float(*coords)[3] = static_cast<float(*)[3]>(
MEM_mallocN(sizeof(*coords) * size_t(coords_len), __func__));
uint(*tris)[3] = static_cast<uint(*)[3]>(
MEM_mallocN(sizeof(*tris) * size_t(corner_tris.size()), __func__));
float(*coords)[3] = MEM_malloc_arrayN<float[3]>(size_t(coords_len), __func__);
uint(*tris)[3] = MEM_malloc_arrayN<uint[3]>(size_t(corner_tris.size()), __func__);
memcpy(coords, mesh->vert_positions().data(), sizeof(float[3]) * size_t(mesh->verts_num));
BVHTree *tree;
@ -1205,12 +1200,10 @@ static PyObject *C_BVHTree_FromObject(PyObject * /*cls*/, PyObject *args, PyObje
tree = BLI_bvhtree_new(
int(corner_tris.size()), epsilon, PY_BVH_TREE_TYPE_DEFAULT, PY_BVH_AXIS_DEFAULT);
if (tree) {
orig_index = static_cast<int *>(
MEM_mallocN(sizeof(*orig_index) * size_t(corner_tris.size()), __func__));
orig_index = MEM_malloc_arrayN<int>(size_t(corner_tris.size()), __func__);
if (!BKE_mesh_face_normals_are_dirty(mesh)) {
const blender::Span<blender::float3> face_normals = mesh->face_normals();
orig_normal = static_cast<blender::float3 *>(
MEM_malloc_arrayN(size_t(mesh->faces_num), sizeof(blender::float3), __func__));
orig_normal = MEM_malloc_arrayN<blender::float3>(size_t(mesh->faces_num), __func__);
blender::MutableSpan(orig_normal, face_normals.size()).copy_from(face_normals);
}

View File

@ -1265,7 +1265,7 @@ static PyObject *M_Geometry_interpolate_bezier(PyObject * /*self*/, PyObject *ar
return nullptr;
}
coord_array = static_cast<float *>(MEM_callocN(dims * (resolu) * sizeof(float), error_prefix));
coord_array = MEM_calloc_arrayN<float>(size_t(dims) * size_t(resolu), error_prefix);
for (i = 0; i < dims; i++) {
BKE_curve_forward_diff_bezier(
UNPACK4_EX(, data, [i]), coord_array + i, resolu - 1, sizeof(float) * dims);
@ -1327,15 +1327,14 @@ static PyObject *M_Geometry_tessellate_polygon(PyObject * /*self*/, PyObject *po
len_polypoints = PySequence_Size(polyLine);
if (len_polypoints > 0) { /* don't bother adding edges as polylines */
dl = static_cast<DispList *>(MEM_callocN(sizeof(DispList), "poly disp"));
dl = MEM_callocN<DispList>("poly disp");
BLI_addtail(&dispbase, dl);
dl->nr = len_polypoints;
dl->type = DL_POLY;
dl->parts = 1; /* no faces, 1 edge loop */
dl->col = 0; /* no material */
dl->verts = fp = static_cast<float *>(
MEM_mallocN(sizeof(float[3]) * len_polypoints, "dl verts"));
dl->index = static_cast<int *>(MEM_callocN(sizeof(int[3]) * len_polypoints, "dl index"));
dl->verts = fp = MEM_malloc_arrayN<float>(3 * size_t(len_polypoints), "dl verts");
dl->index = MEM_calloc_arrayN<int>(3 * size_t(len_polypoints), "dl index");
for (int index = 0; index < len_polypoints; index++, fp += 3) {
polyVec = PySequence_GetItem(polyLine, index);
@ -1409,7 +1408,7 @@ static int boxPack_FromPyObject(PyObject *value, BoxPack **r_boxarray)
len = PyList_GET_SIZE(value);
boxarray = static_cast<BoxPack *>(MEM_mallocN(sizeof(BoxPack) * len, __func__));
boxarray = MEM_malloc_arrayN<BoxPack>(size_t(len), __func__);
for (i = 0; i < len; i++) {
list_item = PyList_GET_ITEM(value, i);
@ -1564,7 +1563,7 @@ static PyObject *M_Geometry_convex_hull_2d(PyObject * /*self*/, PyObject *pointl
int *index_map;
Py_ssize_t len_ret, i;
index_map = static_cast<int *>(MEM_mallocN(sizeof(*index_map) * len, __func__));
index_map = MEM_malloc_arrayN<int>(size_t(len), __func__);
/* Non Python function */
len_ret = BLI_convexhull_2d(points, len, index_map);

View File

@ -65,7 +65,7 @@ static PyObject *M_Interpolate_poly_3d_calc(PyObject * /*self*/, PyObject *args)
}
if (len) {
float *weights = static_cast<float *>(MEM_mallocN(sizeof(float) * len, __func__));
float *weights = MEM_malloc_arrayN<float>(size_t(len), __func__);
interp_weights_poly_v3(weights, vecs, len, fp);

View File

@ -293,7 +293,7 @@ static PyObject *py_kdtree_find_n(PyKDTree *self, PyObject *args, PyObject *kwar
return nullptr;
}
nearest = static_cast<KDTreeNearest_3d *>(MEM_mallocN(sizeof(KDTreeNearest_3d) * n, __func__));
nearest = MEM_malloc_arrayN<KDTreeNearest_3d>(n, __func__);
found = BLI_kdtree_3d_find_nearest_n(self->obj, co, nearest, n);