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); Py_XINCREF(parent);
buffer->parent = parent; buffer->parent = parent;
buffer->ndimensions = ndimensions; buffer->ndimensions = ndimensions;
buffer->dimensions = static_cast<int *>( buffer->dimensions = MEM_malloc_arrayN<int>(size_t(ndimensions), "Buffer dimensions");
MEM_mallocN(ndimensions * sizeof(int), "Buffer dimensions"));
memcpy(buffer->dimensions, dimensions, ndimensions * sizeof(int)); memcpy(buffer->dimensions, dimensions, ndimensions * sizeof(int));
buffer->type = type; buffer->type = type;
buffer->buf.asvoid = buf; 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->itemsize = itemsize;
view->format = (char *)idp_format_from_array_type(prop->subtype); 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; shape[0] = prop->len;
view->shape = shape; 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); 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( if (PyC_AsArray(
new_default_array, sizeof(int), default_value, len, &PyLong_Type, "ui_data_update") == new_default_array, sizeof(int), default_value, len, &PyLong_Type, "ui_data_update") ==
-1) -1)
@ -338,7 +338,7 @@ static bool idprop_ui_data_update_bool_default(IDProperty *idprop,
} }
Py_ssize_t len = PySequence_Size(default_value); 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, if (PyC_AsArray(new_default_array,
sizeof(int8_t), sizeof(int8_t),
default_value, default_value,
@ -428,7 +428,7 @@ static bool idprop_ui_data_update_float_default(IDProperty *idprop,
} }
Py_ssize_t len = PySequence_Size(default_value); 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, if (PyC_AsArray(new_default_array,
sizeof(double), sizeof(double),
default_value, default_value,

View File

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

View File

@ -151,9 +151,8 @@ static BPyGPUBuffer *pygpu_buffer_make_from_data(PyObject *parent,
buffer->parent = nullptr; buffer->parent = nullptr;
buffer->format = format; buffer->format = format;
buffer->shape_len = shape_len; buffer->shape_len = shape_len;
buffer->shape = static_cast<Py_ssize_t *>( buffer->shape = MEM_malloc_arrayN<Py_ssize_t>(size_t(shape_len), "BPyGPUBuffer shape");
MEM_mallocN(shape_len * sizeof(*buffer->shape), "BPyGPUBuffer shape")); memcpy(buffer->shape, shape, sizeof(*buffer->shape) * size_t(shape_len));
memcpy(buffer->shape, shape, shape_len * sizeof(*buffer->shape));
buffer->buf.as_void = buf; buffer->buf.as_void = buf;
if (parent) { if (parent) {
@ -265,14 +264,13 @@ static int pygpu_buffer_dimensions_set(BPyGPUBuffer *self, PyObject *value, void
return -1; return -1;
} }
size_t size = shape_len * sizeof(*self->shape);
if (shape_len != self->shape_len) { if (shape_len != self->shape_len) {
MEM_freeN(self->shape); 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; self->shape_len = shape_len;
memcpy(self->shape, shape, size); memcpy(self->shape, shape, sizeof(*self->shape) * size_t(shape_len));
return 0; return 0;
} }
@ -638,8 +636,7 @@ static int pygpu_buffer__bf_getbuffer(BPyGPUBuffer *self, Py_buffer *view, int f
view->shape = self->shape; view->shape = self->shape;
} }
if (flags & PyBUF_STRIDES) { if (flags & PyBUF_STRIDES) {
view->strides = static_cast<Py_ssize_t *>( view->strides = MEM_malloc_arrayN<Py_ssize_t>(size_t(view->ndim), "BPyGPUBuffer strides");
MEM_mallocN(view->ndim * sizeof(*view->strides), "BPyGPUBuffer strides"));
pygpu_buffer_strides_calc( pygpu_buffer_strides_calc(
eGPUDataFormat(self->format), view->ndim, view->shape, view->strides); 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; return nullptr;
} }
const int coords_size = sizeof(uchar[2]) * tris_len * 3; const size_t items_num = size_t(tris_len) * 3;
const int colors_size = sizeof(uchar[4]) * tris_len * 3; uchar(*coords)[2] = MEM_malloc_arrayN<uchar[2]>(items_num, __func__);
uchar(*coords)[2] = static_cast<uchar(*)[2]>(MEM_mallocN(coords_size, __func__)); uchar(*colors)[4] = MEM_malloc_arrayN<uchar[4]>(items_num, __func__);
uchar(*colors)[4] = static_cast<uchar(*)[4]>(MEM_mallocN(colors_size, __func__));
memcpy(coords, PyBytes_AS_STRING(py_coords), coords_size); memcpy(coords, PyBytes_AS_STRING(py_coords), sizeof(*coords) * items_num);
memcpy(colors, PyBytes_AS_STRING(py_colors), colors_size); 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_len = tris_len;
geom->coords_range[0] = coords_range[0]; geom->coords_range[0] = coords_range[0];
geom->coords_range[1] = coords_range[1]; 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) { if (error_val == 0) {
ReportList *reports; 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. */ /* Own so these don't move into global reports. */
BKE_reports_init(reports, RPT_STORE | RPT_OP_HOLD | RPT_PRINT_HANDLED_BY_OWNER); 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)); BPyPropStore *prop_store = static_cast<BPyPropStore *>(RNA_property_py_data_get(prop));
if (prop_store == nullptr) { 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); RNA_def_py_data(prop, prop_store);
BLI_addtail(&g_bpy_prop_store_list, 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 */ /* blank value */
*r_default_value = 0; *r_default_value = 0;
items = static_cast<EnumPropertyItem *>( items = MEM_calloc_arrayN<EnumPropertyItem>(size_t(seq_len) + 1, "enum_items_from_py1");
MEM_callocN(sizeof(EnumPropertyItem) * (seq_len + 1), "enum_items_from_py1"));
for (i = 0; i < seq_len; i++) { for (i = 0; i < seq_len; i++) {
EnumPropertyItem tmp = {0, "", 0, "", ""}; 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++) { for (int i = 0; i < BPY_GIZMO_FN_SLOT_LEN; i++) {
data->fn_slots[i] = params.py_fn_slots[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) { if (valid) {
PyObject **py_coords_fast_items = PySequence_Fast_ITEMS(py_coords_fast); PyObject **py_coords_fast_items = PySequence_Fast_ITEMS(py_coords_fast);
coords_len = uint(PySequence_Fast_GET_SIZE(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++) { for (i = 0; i < coords_len; i++) {
PyObject *py_vert = py_coords_fast_items[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 */ /* all triangles, simple case */
PyObject **py_tris_fast_items = PySequence_Fast_ITEMS(py_tris_fast); PyObject **py_tris_fast_items = PySequence_Fast_ITEMS(py_tris_fast);
tris_len = uint(PySequence_Fast_GET_SIZE(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++) { for (i = 0; i < tris_len; i++) {
PyObject *py_tricoords = py_tris_fast_items[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. */ /* All NGON's are parsed, now tessellate. */
pf_arena = BLI_memarena_new(BLI_POLYFILL_ARENA_SIZE, __func__); 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_index = MEM_malloc_arrayN<int>(size_t(tris_len), __func__);
orig_normal = static_cast<float(*)[3]>( orig_normal = MEM_malloc_arrayN<float[3]>(size_t(polys_len), __func__);
MEM_mallocN(sizeof(*orig_normal) * size_t(polys_len), __func__));
for (plink = plink_first, poly_index = 0, i = 0; plink; plink = plink->next, poly_index++) { for (plink = plink_first, poly_index = 0, i = 0; plink; plink = plink->next, poly_index++) {
if (plink->len == 3) { if (plink->len == 3) {
@ -966,8 +965,8 @@ static PyObject *C_BVHTree_FromBMesh(PyObject * /*cls*/, PyObject *args, PyObjec
coords_len = uint(bm->totvert); coords_len = uint(bm->totvert);
tris_len = uint(poly_to_tri_count(bm->totface, bm->totloop)); 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__)); coords = MEM_malloc_arrayN<float[3]>(size_t(coords_len), __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__);
blender::Array<std::array<BMLoop *, 3>> corner_tris(tris_len); blender::Array<std::array<BMLoop *, 3>> corner_tris(tris_len);
BM_mesh_calc_tessellation(bm, corner_tris); BM_mesh_calc_tessellation(bm, corner_tris);
@ -985,10 +984,8 @@ static PyObject *C_BVHTree_FromBMesh(PyObject * /*cls*/, PyObject *args, PyObjec
BMFace *f; BMFace *f;
BMVert *v; BMVert *v;
orig_index = static_cast<int *>( orig_index = MEM_malloc_arrayN<int>(size_t(tris_len), __func__);
MEM_mallocN(sizeof(*orig_index) * size_t(tris_len), __func__)); orig_normal = MEM_malloc_arrayN<float[3]>(size_t(bm->totface), __func__);
orig_normal = static_cast<float(*)[3]>(
MEM_mallocN(sizeof(*orig_normal) * size_t(bm->totface), __func__));
BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) { BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) {
copy_v3_v3(coords[i], v->co); 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); const uint coords_len = uint(mesh->verts_num);
float(*coords)[3] = static_cast<float(*)[3]>( float(*coords)[3] = MEM_malloc_arrayN<float[3]>(size_t(coords_len), __func__);
MEM_mallocN(sizeof(*coords) * size_t(coords_len), __func__)); uint(*tris)[3] = MEM_malloc_arrayN<uint[3]>(size_t(corner_tris.size()), __func__);
uint(*tris)[3] = static_cast<uint(*)[3]>(
MEM_mallocN(sizeof(*tris) * size_t(corner_tris.size()), __func__));
memcpy(coords, mesh->vert_positions().data(), sizeof(float[3]) * size_t(mesh->verts_num)); memcpy(coords, mesh->vert_positions().data(), sizeof(float[3]) * size_t(mesh->verts_num));
BVHTree *tree; BVHTree *tree;
@ -1205,12 +1200,10 @@ static PyObject *C_BVHTree_FromObject(PyObject * /*cls*/, PyObject *args, PyObje
tree = BLI_bvhtree_new( tree = BLI_bvhtree_new(
int(corner_tris.size()), epsilon, PY_BVH_TREE_TYPE_DEFAULT, PY_BVH_AXIS_DEFAULT); int(corner_tris.size()), epsilon, PY_BVH_TREE_TYPE_DEFAULT, PY_BVH_AXIS_DEFAULT);
if (tree) { if (tree) {
orig_index = static_cast<int *>( orig_index = MEM_malloc_arrayN<int>(size_t(corner_tris.size()), __func__);
MEM_mallocN(sizeof(*orig_index) * size_t(corner_tris.size()), __func__));
if (!BKE_mesh_face_normals_are_dirty(mesh)) { if (!BKE_mesh_face_normals_are_dirty(mesh)) {
const blender::Span<blender::float3> face_normals = mesh->face_normals(); const blender::Span<blender::float3> face_normals = mesh->face_normals();
orig_normal = static_cast<blender::float3 *>( orig_normal = MEM_malloc_arrayN<blender::float3>(size_t(mesh->faces_num), __func__);
MEM_malloc_arrayN(size_t(mesh->faces_num), sizeof(blender::float3), __func__));
blender::MutableSpan(orig_normal, face_normals.size()).copy_from(face_normals); 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; 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++) { for (i = 0; i < dims; i++) {
BKE_curve_forward_diff_bezier( BKE_curve_forward_diff_bezier(
UNPACK4_EX(, data, [i]), coord_array + i, resolu - 1, sizeof(float) * dims); 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); len_polypoints = PySequence_Size(polyLine);
if (len_polypoints > 0) { /* don't bother adding edges as polylines */ 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); BLI_addtail(&dispbase, dl);
dl->nr = len_polypoints; dl->nr = len_polypoints;
dl->type = DL_POLY; dl->type = DL_POLY;
dl->parts = 1; /* no faces, 1 edge loop */ dl->parts = 1; /* no faces, 1 edge loop */
dl->col = 0; /* no material */ dl->col = 0; /* no material */
dl->verts = fp = static_cast<float *>( dl->verts = fp = MEM_malloc_arrayN<float>(3 * size_t(len_polypoints), "dl verts");
MEM_mallocN(sizeof(float[3]) * len_polypoints, "dl verts")); dl->index = MEM_calloc_arrayN<int>(3 * size_t(len_polypoints), "dl index");
dl->index = static_cast<int *>(MEM_callocN(sizeof(int[3]) * len_polypoints, "dl index"));
for (int index = 0; index < len_polypoints; index++, fp += 3) { for (int index = 0; index < len_polypoints; index++, fp += 3) {
polyVec = PySequence_GetItem(polyLine, index); polyVec = PySequence_GetItem(polyLine, index);
@ -1409,7 +1408,7 @@ static int boxPack_FromPyObject(PyObject *value, BoxPack **r_boxarray)
len = PyList_GET_SIZE(value); 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++) { for (i = 0; i < len; i++) {
list_item = PyList_GET_ITEM(value, 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; int *index_map;
Py_ssize_t len_ret, i; 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 */ /* Non Python function */
len_ret = BLI_convexhull_2d(points, len, index_map); 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) { 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); 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; 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); found = BLI_kdtree_3d_find_nearest_n(self->obj, co, nearest, n);