Sculpt: fix memory corruption

* Fixed a nasty bit of memory corruption
* Along the way, added ASAN support to
  bmesh customdata blocks.
* Each CD layer is padded by 32 bytes
  inside the bmesh data block.
* Also fixed a few minor errors in
  mempool's asan support.
* Tried and failed to fix numerical
  stability issues with lasso/box
  trim brushes.
This commit is contained in:
Joseph Eagar 2021-10-17 01:57:33 -07:00
parent 6d07e148b1
commit f500ef58e2
9 changed files with 520 additions and 62 deletions

View File

@ -997,3 +997,28 @@ BLI_INLINE bool _pbvh_nan_check(const float *co, const char *func, const char *f
return bad;
}
#define PBVH_CHECK_NAN(co) _pbvh_nan_check(co, __func__, __FILE__, __LINE__)
typedef struct DynTopoState DynTopoState;
typedef struct DynRemeshParams {
float edge_size;
float detail_range;
float relax_strength;
} DynRemeshParams;
/*
Simple wrapper api to use the dyntopo remesher in
non-sculpt contexts.
existing_pbvh can be NULL.
Note that all the sculpt customdata layers will be created
if they don't exist, so cd_vert/face_node_offset, cd_mask_offset,
cd_sculpt_vert, etc*/
DynTopoState *BKE_dyntopo_init(struct BMesh *bm, PBVH *existing_pbvh);
void BKE_dyntopo_free(DynTopoState *ds);
void BKE_dyntopo_default_params(DynRemeshParams *params, float edge_size);
void BKE_dyntopo_remesh(DynTopoState *ds,
DynRemeshParams *params,
int steps,
PBVHTopologyUpdateMode mode);

View File

@ -34,6 +34,7 @@
#include "DNA_hair_types.h"
#include "DNA_meshdata_types.h"
#include "BLI_asan.h"
#include "BLI_bitmap.h"
#include "BLI_compiler_attrs.h"
#include "BLI_endian_switch.h"
@ -69,6 +70,8 @@
/* number of layers to add when growing a CustomData object */
#define CUSTOMDATA_GROW 5
#define BM_ASAN_PAD 32
/* ensure typemap size is ok */
BLI_STATIC_ASSERT(ARRAY_SIZE(((CustomData *)NULL)->typemap) == CD_NUMTYPES, "size mismatch");
@ -2577,8 +2580,16 @@ static void customData_update_offsets(CustomData *data)
size += 8 - (size & 7);
}
#if (defined(__SANITIZE_ADDRESS__) || __has_feature(address_sanitizer))
offset += BM_ASAN_PAD;
#endif
data->layers[j].offset = offset;
offset += size;
#if (defined(__SANITIZE_ADDRESS__) || __has_feature(address_sanitizer))
offset += BM_ASAN_PAD;
#endif
}
}
@ -2589,22 +2600,61 @@ static void customData_update_offsets(CustomData *data)
}
typeInfo = layerType_getInfo(data->layers[j].type);
int size = (int)typeInfo->size;
if (i < ARRAY_SIZE(aligns) && typeInfo->size != aligns[i]) {
continue;
}
#if (defined(__SANITIZE_ADDRESS__) || __has_feature(address_sanitizer))
offset += BM_ASAN_PAD;
#endif
BLI_BITMAP_SET(donemap, j, true);
data->layers[j].offset = offset;
offset += typeInfo->size;
offset += size;
#if (defined(__SANITIZE_ADDRESS__) || __has_feature(address_sanitizer))
offset += BM_ASAN_PAD;
#endif
}
}
data->totsize = offset;
CustomData_update_typemap(data);
}
void CustomData_bmesh_asan_poison(const CustomData *data, void *block)
{
#if (defined(__SANITIZE_ADDRESS__) || __has_feature(address_sanitizer))
if (!block) {
return;
}
char *ptr = (char *)block;
BLI_asan_unpoison(block, data->totsize);
for (int i = 0; i < data->totlayer; i++) {
CustomDataLayer *layer = data->layers + i;
const LayerTypeInfo *typeInfo = layerType_getInfo(layer->type);
BLI_asan_poison((ptr + layer->offset - BM_ASAN_PAD), BM_ASAN_PAD);
BLI_asan_poison((ptr + layer->offset + typeInfo->size), BM_ASAN_PAD);
}
#endif
}
void CustomData_bmesh_asan_unpoison(const CustomData *data, void *block)
{
if (!block) {
return;
}
BLI_asan_unpoison(block, data->totsize);
}
/* to use when we're in the middle of modifying layers */
static int CustomData_get_layer_index__notypemap(const CustomData *data, int type)
{
@ -3643,6 +3693,13 @@ int CustomData_get_offset(const CustomData *data, int type)
return data->layers[layer_index].offset;
}
int CustomData_get_named_offset(const CustomData *data, int type, const char *name)
{
int idx = CustomData_get_named_layer_index(data, type, name);
return idx == -1 ? -1 : data->layers[idx].offset;
}
int CustomData_get_n_offset(const CustomData *data, int type, int n)
{
/* get the layer index of the active layer of type */
@ -4025,6 +4082,8 @@ void CustomData_bmesh_free_block(CustomData *data, void **block)
return;
}
CustomData_bmesh_asan_unpoison(data, *block);
for (int i = 0; i < data->totlayer; i++) {
if (!(data->layers[i].flag & CD_FLAG_NOFREE)) {
const LayerTypeInfo *typeInfo = layerType_getInfo(data->layers[i].type);
@ -4051,6 +4110,9 @@ void CustomData_bmesh_free_block_data(CustomData *data, void *block)
if (block == NULL) {
return;
}
CustomData_bmesh_asan_unpoison(data, block);
for (int i = 0; i < data->totlayer; i++) {
if (!(data->layers[i].flag & CD_FLAG_NOFREE)) {
const LayerTypeInfo *typeInfo = layerType_getInfo(data->layers[i].type);
@ -4060,9 +4122,12 @@ void CustomData_bmesh_free_block_data(CustomData *data, void *block)
}
}
}
if (data->totsize) {
memset(block, 0, data->totsize);
}
CustomData_bmesh_asan_poison(data, block);
}
static void CustomData_bmesh_alloc_block(CustomData *data, void **block)
@ -4074,6 +4139,8 @@ static void CustomData_bmesh_alloc_block(CustomData *data, void **block)
if (data->totsize > 0) {
*block = BLI_mempool_alloc(data->pool);
CustomData_bmesh_asan_poison(data, *block);
/*clear toolflags pointer when created for the first time*/
int cd_tflags = data->typemap[CD_TOOLFLAGS];
if (cd_tflags != -1) {
@ -4101,6 +4168,9 @@ void CustomData_bmesh_free_block_data_exclude_by_type(CustomData *data,
if (block == NULL) {
return;
}
CustomData_bmesh_asan_unpoison(data, block);
for (int i = 0; i < data->totlayer; i++) {
if ((CD_TYPE_AS_MASK(data->layers[i].type) & mask_exclude) == 0) {
const LayerTypeInfo *typeInfo = layerType_getInfo(data->layers[i].type);
@ -4113,6 +4183,8 @@ void CustomData_bmesh_free_block_data_exclude_by_type(CustomData *data,
memset(POINTER_OFFSET(block, offset), 0, typeInfo->size);
}
}
CustomData_bmesh_asan_poison(data, block);
}
static void CustomData_bmesh_set_default_n(CustomData *data, void **block, int n)
@ -4146,6 +4218,9 @@ void CustomData_bmesh_set_default(CustomData *data, void **block)
void CustomData_bmesh_swap_data_simple(CustomData *data, void **block1, void **block2)
{
CustomData_bmesh_asan_unpoison(data, *block1);
CustomData_bmesh_asan_unpoison(data, *block2);
int cd_id = data->typemap[CD_MESH_ID];
cd_id = cd_id >= 0 ? data->layers[cd_id].offset : -1;
@ -4178,6 +4253,9 @@ void CustomData_bmesh_swap_data_simple(CustomData *data, void **block1, void **b
*flags2 = tmp;
}
}
CustomData_bmesh_asan_poison(data, *block1);
CustomData_bmesh_asan_poison(data, *block2);
}
void CustomData_bmesh_swap_data(CustomData *source,
@ -4193,7 +4271,10 @@ void CustomData_bmesh_swap_data(CustomData *source,
CustomData_bmesh_alloc_block(dest, dest_block);
if (*dest_block) {
CustomData_bmesh_asan_unpoison(dest, *dest_block);
memset(*dest_block, 0, dest->totsize);
CustomData_bmesh_asan_poison(dest, *dest_block);
CustomData_bmesh_set_default(dest, dest_block);
}
}
@ -4269,8 +4350,11 @@ void CustomData_bmesh_copy_data_exclude_by_type(const CustomData *source,
if (*dest_block == NULL) {
CustomData_bmesh_alloc_block(dest, dest_block);
if (*dest_block) {
CustomData_bmesh_asan_unpoison(dest, *dest_block);
memset(*dest_block, 0, dest->totsize);
CustomData_bmesh_asan_poison(dest, *dest_block);
}
}

View File

@ -612,7 +612,7 @@ BLI_INLINE void surface_smooth_v_safe(PBVH *pbvh, BMVert *v, float fac)
BMVert *v2 = e->v1 == v ? e->v2 : e->v1;
// can't check for boundary here, thread
pbvh_check_vert_boundary(pbvh, v2);
// pbvh_check_vert_boundary(pbvh, v2);
MSculptVert *mv2 = BKE_PBVH_SCULPTVERT(cd_sculpt_vert, v2);
const bool bound2 = mv2->flag & SCULPTVERT_SMOOTH_BOUNDARY;
@ -4668,6 +4668,11 @@ static bool do_cleanup_3_4(EdgeQueueContext *eq_ctx,
return modified;
}
float mask_cb_nop(SculptVertRef vertex, void *userdata)
{
return 1.0f;
}
/* Collapse short edges, subdivide long edges */
bool BKE_pbvh_bmesh_update_topology(PBVH *pbvh,
PBVHTopologyUpdateMode mode,
@ -4749,30 +4754,6 @@ bool BKE_pbvh_bmesh_update_topology(PBVH *pbvh,
safe_smooth = DYNTOPO_SAFE_SMOOTH_FAC;
}
/*
typedef struct EdgeQueueContext {
EdgeQueue *q;
BLI_mempool *pool;
BMesh *bm;
DyntopoMaskCB mask_cb;
void *mask_cb_data;
int cd_sculpt_vert;
int cd_vert_mask_offset;
int cd_vert_node_offset;
int cd_face_node_offset;
float avg_elen;
float max_elen;
float min_elen;
float totedge;
BMVert **val34_verts;
int val34_verts_tot;
int val34_verts_size;
bool local_mode;
float surface_smooth_fac;
} EdgeQueueContext;
*/
EdgeQueueContext eq_ctx = {.q = NULL,
.pool = NULL,
.bm = pbvh->bm,
@ -5702,3 +5683,271 @@ static void pbvh_split_edges(EdgeQueueContext *eq_ctx,
}
#endif
}
extern char dyntopop_node_idx_layer_id[];
extern char dyntopop_faces_areas_layer_id[];
typedef struct DynTopoState {
PBVH *pbvh;
bool is_fake_pbvh;
} DynTopoState;
/* existing_pbvh may be NULL, if so a fake one will be created.
Note that all the sculpt customdata layers will be created
if they don't exist, so cd_vert/face_node_offset, cd_mask_offset,
cd_sculpt_vert, etc*/
DynTopoState *BKE_dyntopo_init(BMesh *bm, PBVH *existing_pbvh)
{
PBVH *pbvh;
PBVHNode _node;
PBVH _start;
if (!existing_pbvh) {
pbvh = MEM_callocN(sizeof(*pbvh), "pbvh");
pbvh->nodes = MEM_callocN(sizeof(PBVHNode), "PBVHNode");
pbvh->type = PBVH_BMESH;
pbvh->totnode = 1;
PBVHNode *node = pbvh->nodes;
node->flag = PBVH_Leaf | PBVH_UpdateTris | PBVH_UpdateTriAreas;
node->bm_faces = BLI_table_gset_new_ex("node->bm_faces", bm->totface);
node->bm_unique_verts = BLI_table_gset_new_ex("node->bm_unique_verts", bm->totvert);
}
else {
pbvh = existing_pbvh;
}
const bool isfake = pbvh != existing_pbvh;
BMCustomLayerReq vlayers[] = {
{CD_PAINT_MASK, NULL, 0},
{CD_DYNTOPO_VERT, NULL, CD_FLAG_TEMPORARY | CD_FLAG_NOCOPY},
{CD_PROP_INT32, dyntopop_node_idx_layer_id, CD_FLAG_TEMPORARY | CD_FLAG_NOCOPY}};
BMCustomLayerReq flayers[] = {
{CD_PROP_FLOAT, dyntopop_faces_areas_layer_id, CD_FLAG_TEMPORARY | CD_FLAG_NOCOPY},
{CD_SCULPT_FACE_SETS, NULL, 0},
{CD_PROP_INT32, dyntopop_node_idx_layer_id, CD_FLAG_TEMPORARY | CD_FLAG_NOCOPY}};
BM_data_layers_ensure(bm, &bm->vdata, vlayers, 3);
BM_data_layers_ensure(bm, &bm->pdata, flayers, 3);
int CustomData_get_named_offset(const CustomData *data, int type, const char *name);
pbvh->bm = bm;
pbvh->cd_vert_node_offset = CustomData_get_named_offset(
&bm->vdata, CD_PROP_INT32, dyntopop_node_idx_layer_id);
pbvh->cd_face_node_offset = CustomData_get_named_offset(
&bm->pdata, CD_PROP_INT32, dyntopop_node_idx_layer_id);
pbvh->cd_face_area = CustomData_get_named_offset(
&bm->pdata, CD_PROP_FLOAT, dyntopop_faces_areas_layer_id);
pbvh->cd_sculpt_vert = CustomData_get_offset(&bm->vdata, CD_DYNTOPO_VERT);
pbvh->cd_vert_mask_offset = CustomData_get_offset(&bm->vdata, CD_PAINT_MASK);
pbvh->cd_faceset_offset = CustomData_get_offset(&bm->pdata, CD_SCULPT_FACE_SETS);
pbvh->cd_vcol_offset = -1;
if (isfake) {
pbvh->bm_log = BM_log_create(bm, pbvh->cd_sculpt_vert);
}
BMVert *v;
BMFace *f;
BMIter iter;
if (isfake) {
BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
BM_ELEM_CD_SET_INT(v, pbvh->cd_vert_node_offset, 0);
BLI_table_gset_add(pbvh->nodes->bm_unique_verts, v);
}
BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
BM_ELEM_CD_SET_INT(f, pbvh->cd_face_node_offset, 0);
BLI_table_gset_add(pbvh->nodes->bm_faces, f);
}
BKE_pbvh_bmesh_check_tris(pbvh, pbvh->nodes);
}
DynTopoState *ds = MEM_callocN(sizeof(DynTopoState), "DynTopoState");
ds->pbvh = pbvh;
ds->is_fake_pbvh = isfake;
return ds;
}
void BKE_dyntopo_default_params(DynRemeshParams *params, float edge_size)
{
memset(params, 0, sizeof(*params));
params->detail_range = 0.45f;
params->edge_size = edge_size;
}
void BKE_dyntopo_free(DynTopoState *ds)
{
if (ds->is_fake_pbvh) {
BM_log_free(ds->pbvh->bm_log, false);
PBVHNode *node = ds->pbvh->nodes;
if (node->tribuf || node->tri_buffers) {
BKE_pbvh_bmesh_free_tris(ds->pbvh, node);
}
BLI_table_gset_free(node->bm_faces, NULL);
BLI_table_gset_free(node->bm_unique_verts, NULL);
MEM_freeN(ds->pbvh->nodes);
MEM_freeN(ds->pbvh);
}
MEM_freeN(ds);
}
/*
bool BKE_pbvh_bmesh_update_topology(PBVH *pbvh,
PBVHTopologyUpdateMode mode,
const float center[3],
const float view_normal[3],
float radius,
const bool use_frontface,
const bool use_projected,
int sym_axis,
bool updatePBVH,
DyntopoMaskCB mask_cb,
void *mask_cb_data,
int custom_max_steps,
bool disable_surface_relax)
*/
void BKE_dyntopo_remesh(DynTopoState *ds,
DynRemeshParams *params,
int steps,
PBVHTopologyUpdateMode mode)
{
float cent[3] = {0.0f, 0.0f, 0.0f};
int totcent = 0;
float view[3] = {0.0f, 0.0f, 1.0f};
BMIter iter;
BMVert *v;
BM_ITER_MESH (v, &iter, ds->pbvh->bm, BM_VERTS_OF_MESH) {
MSculptVert *mv = BKE_PBVH_SCULPTVERT(ds->pbvh->cd_sculpt_vert, v);
mv->flag |= SCULPTVERT_NEED_BOUNDARY | SCULPTVERT_NEED_TRIANGULATE;
mv->valence = BM_vert_edge_count(v);
pbvh_check_vert_boundary(ds->pbvh, v);
add_v3_v3(cent, v->co);
totcent;
}
if (totcent) {
mul_v3_fl(cent, 1.0f / (float)totcent);
}
ds->pbvh->bm_max_edge_len = params->edge_size;
ds->pbvh->bm_min_edge_len = params->edge_size * params->detail_range;
ds->pbvh->bm_detail_range = params->detail_range;
/* subdivide once */
if (mode & PBVH_Subdivide) {
BKE_pbvh_bmesh_update_topology(ds->pbvh,
PBVH_Subdivide,
cent,
view,
1e17,
false,
false,
0,
false,
mask_cb_nop,
NULL,
ds->pbvh->bm->totedge,
false);
}
for (int i = 0; i < steps; i++) {
for (int j = 0; j < ds->pbvh->totnode; j++) {
PBVHNode *node = ds->pbvh->nodes + j;
if (node->flag & PBVH_Leaf) {
node->flag |= PBVH_UpdateTopology;
}
}
BKE_pbvh_bmesh_update_topology(ds->pbvh,
mode,
cent,
view,
1e17,
false,
false,
0,
false,
mask_cb_nop,
NULL,
ds->pbvh->bm->totedge * 5,
true);
BKE_pbvh_update_normals(ds->pbvh, NULL);
BM_ITER_MESH (v, &iter, ds->pbvh->bm, BM_VERTS_OF_MESH) {
MSculptVert *mv = BKE_PBVH_SCULPTVERT(ds->pbvh->cd_sculpt_vert, v);
pbvh_check_vert_boundary(ds->pbvh, v);
float avg[3] = {0.0f, 0.0f, 0.0f};
float totw = 0.0f;
bool bound1 = mv->flag & SCULPTVERT_ALL_BOUNDARY;
if (bound1) {
continue;
}
if (mv->flag & SCULPTVERT_ALL_CORNER) {
continue;
}
if (!v->e) {
continue;
}
BMEdge *e = v->e;
do {
BMVert *v2 = BM_edge_other_vert(e, v);
MSculptVert *mv2 = BKE_PBVH_SCULPTVERT(ds->pbvh->cd_sculpt_vert, v2);
pbvh_check_vert_boundary(ds->pbvh, v2);
bool bound2 = mv2->flag & SCULPTVERT_ALL_BOUNDARY;
if (bound1 && !bound2) {
continue;
}
float tmp[3];
float w = 1.0f;
sub_v3_v3v3(tmp, v2->co, v->co);
madd_v3_v3fl(tmp, v->no, -dot_v3v3(v->no, tmp) * 0.75);
add_v3_v3(tmp, v->co);
madd_v3_v3fl(avg, tmp, w);
totw += w;
} while ((e = BM_DISK_EDGE_NEXT(e, v)) != v->e);
if (totw == 0.0f) {
continue;
}
mul_v3_fl(avg, 1.0f / totw);
interp_v3_v3v3(v->co, v->co, avg, 0.5f);
}
}
}

View File

@ -52,6 +52,7 @@
#if (defined(__SANITIZE_ADDRESS__) || __has_feature(address_sanitizer))
# define POISON_REDZONE_SIZE 32
# define HAVE_MEMPOOL_ASAN
#else
# define POISON_REDZONE_SIZE 0
#endif
@ -141,12 +142,16 @@ struct BLI_mempool {
uint flag;
/* keeps aligned to 16 bits */
#ifdef HAVE_MEMPOOL_ASAN
char poisoned[256];
#endif
/** Free element list. Interleaved into chunk datas. */
BLI_freenode *free;
/** Use to know how many chunks to keep for #BLI_mempool_clear. */
uint maxchunks;
/** Number of elements currently in use. */
uint totused;
int totused;
#ifdef USE_TOTALLOC
/** Number of elements allocated in total. */
uint totalloc;
@ -227,7 +232,7 @@ BLI_INLINE uint mempool_maxchunks(const uint totelem, const uint pchunk)
static BLI_mempool_chunk *mempool_chunk_alloc(BLI_mempool *pool)
{
return MEM_mallocN(sizeof(BLI_mempool_chunk) + (size_t)pool->csize, pool->memtag);
return BLI_asan_safe_malloc(sizeof(BLI_mempool_chunk) + (size_t)pool->csize, pool->memtag);
}
/**
@ -289,7 +294,7 @@ static BLI_freenode *mempool_chunk_add(BLI_mempool *pool,
while (j--) {
BLI_freenode *next;
BLI_asan_unpoison(curnode, pool->esize);
BLI_asan_unpoison(curnode, pool->esize - POISON_REDZONE_SIZE);
curnode->next = next = NODE_STEP_NEXT(curnode);
curnode->freeword = FREEWORD;
@ -303,7 +308,7 @@ static BLI_freenode *mempool_chunk_add(BLI_mempool *pool,
while (j--) {
BLI_freenode *next;
BLI_asan_unpoison(curnode, pool->esize);
BLI_asan_unpoison(curnode, pool->esize - POISON_REDZONE_SIZE);
curnode->next = next = NODE_STEP_NEXT(curnode);
BLI_asan_poison(curnode, pool->esize);
@ -314,13 +319,13 @@ static BLI_freenode *mempool_chunk_add(BLI_mempool *pool,
/* terminate the list (rewind one)
* will be overwritten if 'curnode' gets passed in again as 'last_tail' */
BLI_asan_unpoison(curnode, pool->esize);
BLI_asan_unpoison(curnode, pool->esize - POISON_REDZONE_SIZE);
BLI_freenode *prev = NODE_STEP_PREV(curnode);
BLI_asan_poison(curnode, pool->esize);
curnode = NODE_STEP_PREV(curnode);
BLI_asan_unpoison(curnode, pool->esize);
BLI_asan_unpoison(curnode, pool->esize - POISON_REDZONE_SIZE);
curnode->next = NULL;
BLI_asan_poison(curnode, pool->esize);
@ -330,7 +335,7 @@ static BLI_freenode *mempool_chunk_add(BLI_mempool *pool,
/* final pointer in the previously allocated chunk is wrong */
if (last_tail) {
BLI_asan_unpoison(last_tail, pool->esize);
BLI_asan_unpoison(last_tail, pool->esize - POISON_REDZONE_SIZE);
last_tail->next = CHUNK_DATA(mpchunk);
BLI_asan_poison(last_tail, pool->esize);
}
@ -389,7 +394,7 @@ BLI_mempool *BLI_mempool_create_for_tasks(const unsigned int esize,
chunk = chunk->next;
}
pool->totused = totalloc;
pool->totused = (int)totalloc;
pool->free = NULL;
int i = (int)pool->pchunk - 1;
@ -442,7 +447,7 @@ BLI_mempool *BLI_mempool_create_for_tasks(const unsigned int esize,
static void mempool_chunk_free(BLI_mempool_chunk *mpchunk, BLI_mempool *pool)
{
BLI_asan_unpoison(mpchunk, sizeof(BLI_mempool_chunk) + pool->esize * pool->csize);
MEM_freeN(mpchunk);
BLI_asan_safe_free(mpchunk);
}
static void mempool_chunk_free_all(BLI_mempool_chunk *mpchunk, BLI_mempool *pool)
@ -548,6 +553,10 @@ BLI_mempool *BLI_mempool_create_ex(
VALGRIND_CREATE_MEMPOOL(pool, 0, false);
#endif
#ifdef HAVE_MEMPOOL_ASAN
BLI_asan_poison(pool->poisoned, sizeof(pool->poisoned));
#endif
return pool;
}
@ -634,7 +643,7 @@ int BLI_mempool_find_elems_fuzzy(
char *data = (char *)CHUNK_DATA(chunk);
void *ptr = data + idx2 * (int)pool->esize;
BLI_asan_unpoison(ptr, pool->esize);
BLI_asan_unpoison(ptr, pool->esize - POISON_REDZONE_SIZE);
BLI_freenode *fnode = (BLI_freenode *)ptr;
if (fnode->freeword == FREEWORD) {
@ -711,6 +720,12 @@ void BLI_mempool_free(BLI_mempool *pool, void *addr)
pool->totused--;
if (pool->totused < 0) {
fprintf(stderr, "Corrupted mempool\n");
fflush(stderr);
abort();
}
#ifdef WITH_MEM_VALGRIND
VALGRIND_MEMPOOL_FREE(pool, addr);
#endif
@ -743,19 +758,19 @@ void BLI_mempool_free(BLI_mempool *pool, void *addr)
j = pool->pchunk;
while (j--) {
BLI_asan_unpoison(curnode, pool->esize);
BLI_asan_unpoison(curnode, pool->esize - POISON_REDZONE_SIZE);
BLI_freenode *next = curnode->next = NODE_STEP_NEXT(curnode);
BLI_asan_poison(curnode, pool->esize);
curnode = next;
}
BLI_asan_unpoison(curnode, pool->esize);
BLI_asan_unpoison(curnode, pool->esize - POISON_REDZONE_SIZE);
BLI_freenode *prev = NODE_STEP_PREV(curnode);
BLI_asan_poison(curnode, pool->esize);
curnode = prev;
BLI_asan_unpoison(curnode, pool->esize);
BLI_asan_unpoison(curnode, pool->esize - POISON_REDZONE_SIZE);
curnode->next = NULL; /* terminate the list */
BLI_asan_poison(curnode, pool->esize);
@ -767,14 +782,14 @@ void BLI_mempool_free(BLI_mempool *pool, void *addr)
int BLI_mempool_len(const BLI_mempool *pool)
{
return (int)pool->totused;
return pool->totused;
}
void *BLI_mempool_findelem(BLI_mempool *pool, uint index)
{
BLI_assert(pool->flag & BLI_MEMPOOL_ALLOW_ITER);
if (index < pool->totused) {
if (index < (uint)pool->totused) {
/* We could have some faster mem chunk stepping code inline. */
BLI_mempool_iter iter;
void *elem;
@ -805,7 +820,7 @@ void BLI_mempool_as_table(BLI_mempool *pool, void **data)
while ((elem = BLI_mempool_iterstep(&iter))) {
*p++ = elem;
}
BLI_assert((uint)(p - data) == pool->totused);
BLI_assert((int)(p - data) == pool->totused);
}
/**
@ -832,7 +847,7 @@ void BLI_mempool_as_array(BLI_mempool *pool, void *data)
memcpy(p, elem, (size_t)esize);
p = NODE_STEP_NEXT(p);
}
BLI_assert((uint)(p - (char *)data) == pool->totused * esize);
BLI_assert((int)(p - (char *)data) == pool->totused * esize);
}
/**
@ -1141,6 +1156,10 @@ void BLI_mempool_destroy(BLI_mempool *pool)
VALGRIND_DESTROY_MEMPOOL(pool);
#endif
#ifdef HAVE_MEMPOOL_ASAN
BLI_asan_unpoison(pool->poisoned, sizeof(pool->poisoned));
#endif
MEM_freeN(pool);
}

View File

@ -812,6 +812,8 @@ int bmesh_elem_check(void *element, const char htype)
#endif /* NDEBUG */
int bleh = 0;
/**
* low level function, only frees the vert,
* doesn't change or adjust surrounding geometry
@ -832,6 +834,11 @@ static void bm_kill_only_vert(BMesh *bm, BMVert *v)
v, bm->vdata.layers[bm->vdata.typemap[CD_TOOLFLAGS]].offset);
BLI_mempool_free(bm->vtoolflagpool, flags->flag);
flags->flag = NULL;
if (bleh) {
printf("eek\n");
}
}
if (v->head.data) {
@ -969,7 +976,7 @@ void bm_kill_only_face(BMesh *bm, BMFace *f)
MToolFlags *flags = BM_ELEM_CD_GET_VOID_P(
f, bm->pdata.layers[bm->pdata.typemap[CD_TOOLFLAGS]].offset);
BLI_mempool_free(bm->vtoolflagpool, flags->flag);
BLI_mempool_free(bm->ftoolflagpool, flags->flag);
}
if (f->head.data) {

View File

@ -1438,10 +1438,25 @@ void BM_data_layers_ensure(BMesh *bm, CustomData *data, BMCustomLayerReq *layers
return;
}
CustomDataLayer **nocopy_layers = NULL;
BLI_array_declare(nocopy_layers);
for (int i = 0; i < data->totlayer; i++) {
if (data->layers[i].flag & CD_FLAG_NOCOPY) {
BLI_array_append(nocopy_layers, &data->layers[i]);
}
}
if (modified) {
CustomData_merge(&temp, data, mask, CD_ASSIGN, 0);
}
for (int i = 0; i < BLI_array_len(nocopy_layers); i++) {
nocopy_layers[i]->flag |= CD_FLAG_NOCOPY;
}
BLI_array_free(nocopy_layers);
for (int i = 0; i < totlayer; i++) {
BMCustomLayerReq *req = layers + i;
int idx;

View File

@ -59,6 +59,9 @@
#define CUSTOMDATA
void CustomData_bmesh_asan_unpoison(const CustomData *data, void *block);
void CustomData_bmesh_asan_poison(const CustomData *data, void *block);
//#define DEBUG_LOG_TO_FILE
//#define DO_LOG_PRINT
@ -685,6 +688,7 @@ static void bm_log_vert_customdata(
//}
if (lv->customdata) {
CustomData_bmesh_asan_unpoison(&entry->vdata, lv->customdata);
BLI_mempool_free(entry->vdata.pool, lv->customdata);
lv->customdata = NULL;
}
@ -701,6 +705,7 @@ static void bm_log_edge_customdata(
BMesh *bm, BMLog *log, BMLogEntry *entry, BMEdge *e, BMLogEdge *le)
{
if (le->customdata) {
CustomData_bmesh_asan_unpoison(&entry->edata, le->customdata);
BLI_mempool_free(entry->edata.pool, le->customdata);
le->customdata = NULL;
}
@ -718,6 +723,7 @@ static void bm_log_face_customdata(BMesh *bm, BMLog *log, BMFace *f, BMLogFace *
}
if (lf->customdata_f) {
CustomData_bmesh_asan_unpoison(&entry->pdata, lf->customdata_f);
BLI_mempool_free(entry->pdata.pool, lf->customdata_f);
lf->customdata_f = NULL;
}
@ -731,6 +737,7 @@ static void bm_log_face_customdata(BMesh *bm, BMLog *log, BMFace *f, BMLogFace *
int i = 0;
do {
if (lf->customdata[i]) {
CustomData_bmesh_asan_unpoison(&entry->ldata, lf->customdata[i]);
BLI_mempool_free(entry->ldata.pool, lf->customdata[i]);
lf->customdata[i] = NULL;
}
@ -902,12 +909,14 @@ static void bm_log_face_bmface_copy(
// free existing customdata blocks
if (lf->customdata_f) {
CustomData_bmesh_asan_unpoison(&entry->pdata, lf->customdata_f);
BLI_mempool_free(entry->pdata.pool, lf->customdata_f);
lf->customdata_f = NULL;
}
for (uint i = 0; i < lf->len; i++) {
if (lf->customdata[i]) {
CustomData_bmesh_asan_unpoison(&entry->ldata, lf->customdata[i]);
BLI_mempool_free(entry->ldata.pool, lf->customdata[i]);
lf->customdata[i] = NULL;
}
@ -1438,7 +1447,10 @@ static void bm_log_vert_values_swap(
if (lv->customdata) {
if (v->head.data) {
old_cdata = scratch;
CustomData_bmesh_asan_unpoison(&bm->vdata, v->head.data);
memcpy(old_cdata, v->head.data, (size_t)bm->vdata.totsize);
CustomData_bmesh_asan_poison(&bm->vdata, v->head.data);
}
CustomData_bmesh_swap_data(&entry->vdata, &bm->vdata, lv->customdata, &v->head.data);
@ -1471,7 +1483,9 @@ static void bm_log_edge_values_swap(
if (le->customdata) {
if (e->head.data) {
old_cdata = scratch;
CustomData_bmesh_asan_unpoison(&bm->edata, e->head.data);
memcpy(old_cdata, e->head.data, (size_t)bm->edata.totsize);
CustomData_bmesh_asan_poison(&bm->edata, e->head.data);
}
CustomData_bmesh_swap_data(&entry->edata, &bm->edata, le->customdata, &e->head.data);
@ -1506,7 +1520,9 @@ static void bm_log_face_values_swap(BMLog *log,
if (f->head.data) {
old_cdata = scratch;
CustomData_bmesh_asan_unpoison(&log->bm->pdata, f->head.data);
memcpy(old_cdata, f->head.data, (size_t)log->bm->pdata.totsize);
CustomData_bmesh_asan_poison(&log->bm->pdata, f->head.data);
}
if (lf->customdata_f) {
@ -1869,16 +1885,6 @@ static bool bm_log_free_direct(BMLog *log, bool safe_mode)
BMLogEntry *entry;
if (safe_mode && log->refcount) {
#if 0
if (log->frozen_full_mesh) {
log->frozen_full_mesh->log = NULL;
bm_log_entry_free(log->frozen_full_mesh);
}
#endif
// log->frozen_full_mesh = bm_log_entry_create(LOG_ENTRY_FULL_MESH);
// bm_log_full_mesh_intern(log->bm, log, log->frozen_full_mesh);
return false;
}
@ -2965,6 +2971,7 @@ void BM_log_face_topo_post(BMLog *log, BMFace *f)
if (BLI_ghash_ensure_p(entry->topo_modified_faces_post, key, &val)) {
BMLogFace *lf_old = (BMLogFace *)*val;
*lf_old = *lf;
BLI_mempool_free(entry->pool_faces, lf);
}
else {

View File

@ -63,8 +63,11 @@ static BMVert *bmo_vert_copy(BMOperator *op,
/* Handle Ids */
bm_alloc_id(bm_dst, (BMElem *)v_dst);
bm_elem_check_toolflags(bm_dst, (BMElem *)v_dst);
// short **flags = BM_ELEM_CD_GET_VOID_P(
// v_dst, bm_dst->vdata.layers[bm_dst->vdata.typemap[CD_TOOLFLAGS]].offset);
bm_elem_check_toolflags(bm_dst, (BMElem *)v_dst);
// printf("%p\n", flags);
/* Mark the vert for output */
BMO_vert_flag_enable(bm_dst, v_dst, DUPE_NEW);

View File

@ -973,6 +973,7 @@ typedef struct SculptGestureTrimOperation {
float depth_front;
float depth_back;
float avg_edge_len;
bool use_cursor_depth;
@ -1171,6 +1172,17 @@ static void sculpt_gesture_trim_geometry_generate(SculptGestureContext *sgcontex
mul_v3_m4v3(trim_operation->true_mesh_co[i], ob_imat, new_point);
}
float avg_elen = 0.0f;
for (int i = 0; i < tot_screen_points; i++) {
MVert *v1 = trim_operation->mesh->mvert + i;
MVert *v2 = trim_operation->mesh->mvert + ((i + 1) % tot_screen_points);
avg_elen += len_v3v3(v1->co, v2->co);
}
trim_operation->avg_edge_len = avg_elen / (float)tot_screen_points;
/* Write vertices coordinates for the back face. */
madd_v3_v3v3fl(depth_point, shape_origin, shape_normal, depth_back);
for (int i = 0; i < tot_screen_points; i++) {
@ -1242,8 +1254,16 @@ static void sculpt_gesture_trim_geometry_generate(SculptGestureContext *sgcontex
BKE_mesh_calc_edges(trim_operation->mesh, false, false);
sculpt_gesture_trim_normals_update(sgcontext);
}
mp = trim_operation->mesh->mpoly + tot_tris_face * 2;
/* flag edges as sharp for dyntopo remesher */
for (int i = 0; i < tot_screen_points * 2; i++, mp++) {
ml = trim_operation->mesh->mloop + mp->loopstart;
trim_operation->mesh->medge[ml[1].e].flag |= ME_SHARP;
}
}
static void sculpt_gesture_trim_geometry_free(SculptGestureContext *sgcontext)
{
SculptGestureTrimOperation *trim_operation = (SculptGestureTrimOperation *)sgcontext->operation;
@ -1284,13 +1304,45 @@ static void sculpt_gesture_apply_trim(SculptGestureContext *sgcontext)
}));
}
const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(sculpt_mesh, trim_mesh);
BMesh *trimbm = BM_mesh_create(
&allocsize,
&((struct BMeshCreateParams){.use_toolflags = false,
.create_unique_ids = true,
.no_reuse_ids = false,
.temporary_ids = false,
.copy_all_layers = true,
.id_elem_mask = BM_VERT | BM_EDGE | BM_FACE,
.id_map = true}));
BM_mesh_bm_from_me(NULL,
bm,
trimbm,
trim_mesh,
&((struct BMeshFromMeshParams){
.calc_face_normal = true,
}));
BM_mesh_normals_update(bm);
#if 0
// remesh
DynTopoState *ds = BKE_dyntopo_init(trimbm, NULL);
DynRemeshParams params;
BKE_dyntopo_default_params(&params, trim_operation->avg_edge_len * 4.0);
BKE_dyntopo_remesh(ds, &params, 10, PBVH_Collapse | PBVH_Cleanup | PBVH_Subdivide);
BM_mesh_toolflags_set(bm, true);
BKE_dyntopo_free(ds);
#endif
BM_mesh_toolflags_set(bm, true);
BMO_op_callf(trimbm, BMO_FLAG_DEFAULTS, "duplicate geom=%avef dest=%p", bm, 3);
SCULPT_update_customdata_refs(sgcontext->ss);
BM_mesh_free(trimbm);
const int looptris_tot = poly_to_tri_count(bm->totface, bm->totloop);
BMLoop *(*looptris)[3];
looptris = MEM_malloc_arrayN(looptris_tot, sizeof(*looptris), __func__);
@ -1409,10 +1461,6 @@ static void sculpt_gesture_trim_end(bContext *UNUSED(C), SculptGestureContext *s
sculpt_gesture_trim_geometry_free(sgcontext);
if (sgcontext->ss && sgcontext->ss->bm) {
SCULPT_dynamic_topology_triangulate(sgcontext->ss, sgcontext->ss->bm);
}
SCULPT_undo_push_node(sgcontext->vc.obact, NULL, SCULPT_UNDO_GEOMETRY);
BKE_mesh_batch_cache_dirty_tag(sgcontext->vc.obact->data, BKE_MESH_BATCH_DIRTY_ALL);
DEG_id_tag_update(&sgcontext->vc.obact->id, ID_RECALC_GEOMETRY);
@ -1828,7 +1876,8 @@ static int sculpt_trim_gesture_lasso_exec(bContext *C, wmOperator *op)
{
Object *object = CTX_data_active_object(C);
SculptSession *ss = object->sculpt;
if (BKE_pbvh_type(ss->pbvh) != PBVH_FACES) {
if (BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS) {
/* Not supported in Multires and Dyntopo. */
return OPERATOR_CANCELLED;
}