Commit: 602250d9fe796ff5e762a4880a0be97ef3f4b139
Author: Campbell Barton
Date:   Wed Dec 10 11:06:00 2014 +0100
Branches: master
https://developer.blender.org/rB602250d9fe796ff5e762a4880a0be97ef3f4b139

Fix T42748: Crash in subsurf, threaded access

Allocating the iterator from a BLI_memarena wasn't threadsafe.
Change the API to use stack memory for iterators.

Thanks to @mont29 for finding exact cause of the bug.

===================================================================

M       source/blender/blenkernel/intern/CCGSubSurf.c
M       source/blender/blenkernel/intern/CCGSubSurf.h
M       source/blender/blenkernel/intern/subsurf_ccg.c

===================================================================

diff --git a/source/blender/blenkernel/intern/CCGSubSurf.c 
b/source/blender/blenkernel/intern/CCGSubSurf.c
index 623fb50..9e5d4af 100644
--- a/source/blender/blenkernel/intern/CCGSubSurf.c
+++ b/source/blender/blenkernel/intern/CCGSubSurf.c
@@ -172,29 +172,19 @@ static void *_ehash_lookup(EHash *eh, void *key)
 
 /**/
 
-typedef struct _EHashIterator {
-       EHash *eh;
-       int curBucket;
-       EHEntry *curEntry;
-} EHashIterator;
-
-static EHashIterator *_ehashIterator_new(EHash *eh)
+static void _ehashIterator_init(EHash *eh, EHashIterator *ehi)
 {
-       EHashIterator *ehi = EHASH_alloc(eh, sizeof(*ehi));
+       /* fill all members */
        ehi->eh = eh;
-       ehi->curEntry = NULL;
        ehi->curBucket = -1;
+       ehi->curEntry = NULL;
+
        while (!ehi->curEntry) {
                ehi->curBucket++;
                if (ehi->curBucket == ehi->eh->curSize)
                        break;
                ehi->curEntry = ehi->eh->buckets[ehi->curBucket];
        }
-       return ehi;
-}
-static void _ehashIterator_free(EHashIterator *ehi)
-{
-       EHASH_free(ehi->eh, ehi);
 }
 
 static void *_ehashIterator_getCurrent(EHashIterator *ehi)
@@ -3051,17 +3041,17 @@ void *ccgSubSurf_getFaceGridData(CCGSubSurf *ss, 
CCGFace *f, int gridIndex, int
 
 /*** External API iterator functions ***/
 
-CCGVertIterator *ccgSubSurf_getVertIterator(CCGSubSurf *ss)
+void ccgSubSurf_initVertIterator(CCGSubSurf *ss, CCGVertIterator *viter)
 {
-       return (CCGVertIterator *) _ehashIterator_new(ss->vMap);
+       _ehashIterator_init(ss->vMap, viter);
 }
-CCGEdgeIterator *ccgSubSurf_getEdgeIterator(CCGSubSurf *ss)
+void ccgSubSurf_initEdgeIterator(CCGSubSurf *ss, CCGEdgeIterator *eiter)
 {
-       return (CCGEdgeIterator *) _ehashIterator_new(ss->eMap);
+       _ehashIterator_init(ss->eMap, eiter);
 }
-CCGFaceIterator *ccgSubSurf_getFaceIterator(CCGSubSurf *ss)
+void ccgSubSurf_initFaceIterator(CCGSubSurf *ss, CCGFaceIterator *fiter)
 {
-       return (CCGFaceIterator *) _ehashIterator_new(ss->fMap);
+       _ehashIterator_init(ss->fMap, fiter);
 }
 
 CCGVert *ccgVertIterator_getCurrent(CCGVertIterator *vi)
@@ -3076,10 +3066,6 @@ void ccgVertIterator_next(CCGVertIterator *vi)
 {
        _ehashIterator_next((EHashIterator *) vi);
 }
-void ccgVertIterator_free(CCGVertIterator *vi)
-{
-       _ehashIterator_free((EHashIterator *) vi);
-}
 
 CCGEdge *ccgEdgeIterator_getCurrent(CCGEdgeIterator *vi)
 {
@@ -3093,10 +3079,6 @@ void ccgEdgeIterator_next(CCGEdgeIterator *vi)
 {
        _ehashIterator_next((EHashIterator *) vi);
 }
-void ccgEdgeIterator_free(CCGEdgeIterator *vi)
-{
-       _ehashIterator_free((EHashIterator *) vi);
-}
 
 CCGFace *ccgFaceIterator_getCurrent(CCGFaceIterator *vi)
 {
@@ -3110,10 +3092,6 @@ void ccgFaceIterator_next(CCGFaceIterator *vi)
 {
        _ehashIterator_next((EHashIterator *) vi);
 }
-void ccgFaceIterator_free(CCGFaceIterator *vi)
-{
-       _ehashIterator_free((EHashIterator *) vi);
-}
 
 /*** Extern API final vert/edge/face interface ***/
 
diff --git a/source/blender/blenkernel/intern/CCGSubSurf.h 
b/source/blender/blenkernel/intern/CCGSubSurf.h
index fdf6d2d..2b86a2a 100644
--- a/source/blender/blenkernel/intern/CCGSubSurf.h
+++ b/source/blender/blenkernel/intern/CCGSubSurf.h
@@ -53,6 +53,13 @@ typedef struct CCGAllocatorIFC {
        void            (*release)                      (CCGAllocatorHDL a);
 } CCGAllocatorIFC;
 
+/* private, so we can allocate on the stack */
+typedef struct _EHashIterator {
+       struct _EHash *eh;
+       int curBucket;
+       struct _EHEntry *curEntry;
+} EHashIterator;
+
 /***/
 
 typedef enum {
@@ -163,27 +170,24 @@ int                       ccgSubSurf_getNumFinalFaces     
        (const CCGSubSurf *ss);
 
 /***/
 
-typedef struct CCGVertIterator CCGVertIterator;
-typedef struct CCGEdgeIterator CCGEdgeIterator;
-typedef struct CCGFaceIterator CCGFaceIterator;
+typedef struct _EHashIterator CCGVertIterator;
+typedef struct _EHashIterator CCGEdgeIterator;
+typedef struct _EHashIterator CCGFaceIterator;
 
-CCGVertIterator*       ccgSubSurf_getVertIterator      (CCGSubSurf *ss);
-CCGEdgeIterator*       ccgSubSurf_getEdgeIterator      (CCGSubSurf *ss);
-CCGFaceIterator*       ccgSubSurf_getFaceIterator      (CCGSubSurf *ss);
+void           ccgSubSurf_initVertIterator(CCGSubSurf *ss, CCGVertIterator 
*viter);
+void           ccgSubSurf_initEdgeIterator(CCGSubSurf *ss, CCGEdgeIterator 
*eiter);
+void           ccgSubSurf_initFaceIterator(CCGSubSurf *ss, CCGFaceIterator 
*fiter);
 
 CCGVert*                       ccgVertIterator_getCurrent      
(CCGVertIterator *vi);
 int                                    ccgVertIterator_isStopped       
(CCGVertIterator *vi);
 void                           ccgVertIterator_next            
(CCGVertIterator *vi);
-void                           ccgVertIterator_free            
(CCGVertIterator *vi);
 
 CCGEdge*                       ccgEdgeIterator_getCurrent      
(CCGEdgeIterator *ei);
 int                                    ccgEdgeIterator_isStopped       
(CCGEdgeIterator *ei);
 void                           ccgEdgeIterator_next            
(CCGEdgeIterator *ei);
-void                           ccgEdgeIterator_free            
(CCGEdgeIterator *ei);
 
 CCGFace*                       ccgFaceIterator_getCurrent      
(CCGFaceIterator *fi);
 int                                    ccgFaceIterator_isStopped       
(CCGFaceIterator *fi);
 void                           ccgFaceIterator_next            
(CCGFaceIterator *fi);
-void                           ccgFaceIterator_free            
(CCGFaceIterator *fi);
 
 #endif  /* __CCGSUBSURF_H__ */
diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c 
b/source/blender/blenkernel/intern/subsurf_ccg.c
index 12d7409..c777fcd 100644
--- a/source/blender/blenkernel/intern/subsurf_ccg.c
+++ b/source/blender/blenkernel/intern/subsurf_ccg.c
@@ -407,7 +407,7 @@ static void set_subsurf_uv(CCGSubSurf *ss, DerivedMesh *dm, 
DerivedMesh *result,
        CCGFace **faceMap;
        MTFace *tf;
        MLoopUV *mluv;
-       CCGFaceIterator *fi;
+       CCGFaceIterator fi;
        int index, gridSize, gridFaces, /*edgeSize,*/ totface, x, y, S;
        MLoopUV *dmloopuv = CustomData_get_layer_n(&dm->loopData, CD_MLOOPUV, 
n);
        /* need to update both CD_MTFACE & CD_MLOOPUV, hrmf, we could get away 
with
@@ -434,11 +434,10 @@ static void set_subsurf_uv(CCGSubSurf *ss, DerivedMesh 
*dm, DerivedMesh *result,
 
        /* make a map from original faces to CCGFaces */
        faceMap = MEM_mallocN(totface * sizeof(*faceMap), "facemapuv");
-       for (fi = ccgSubSurf_getFaceIterator(uvss); 
!ccgFaceIterator_isStopped(fi); ccgFaceIterator_next(fi)) {
-               CCGFace *f = ccgFaceIterator_getCurrent(fi);
+       for (ccgSubSurf_initFaceIterator(uvss, &fi); 
!ccgFaceIterator_isStopped(&fi); ccgFaceIterator_next(&fi)) {
+               CCGFace *f = ccgFaceIterator_getCurrent(&fi);
                faceMap[GET_INT_FROM_POINTER(ccgSubSurf_getFaceFaceHandle(f))] 
= f;
        }
-       ccgFaceIterator_free(fi);
 
        /* load coordinates from uvss into tface */
        tf = tface;
@@ -695,9 +694,9 @@ static void ccgDM_getMinMax(DerivedMesh *dm, float 
r_min[3], float r_max[3])
 {
        CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
        CCGSubSurf *ss = ccgdm->ss;
-       CCGVertIterator *vi;
-       CCGEdgeIterator *ei;
-       CCGFaceIterator *fi;
+       CCGVertIterator vi;
+       CCGEdgeIterator ei;
+       CCGFaceIterator fi;
        CCGKey key;
        int i, edgeSize = ccgSubSurf_getEdgeSize(ss);
        int gridSize = ccgSubSurf_getGridSize(ss);
@@ -707,25 +706,23 @@ static void ccgDM_getMinMax(DerivedMesh *dm, float 
r_min[3], float r_max[3])
        if (!ccgSubSurf_getNumVerts(ss))
                r_min[0] = r_min[1] = r_min[2] = r_max[0] = r_max[1] = r_max[2] 
= 0.0;
 
-       for (vi = ccgSubSurf_getVertIterator(ss); 
!ccgVertIterator_isStopped(vi); ccgVertIterator_next(vi)) {
-               CCGVert *v = ccgVertIterator_getCurrent(vi);
+       for (ccgSubSurf_initVertIterator(ss, &vi); 
!ccgVertIterator_isStopped(&vi); ccgVertIterator_next(&vi)) {
+               CCGVert *v = ccgVertIterator_getCurrent(&vi);
                float *co = ccgSubSurf_getVertData(ss, v);
 
                minmax_v3_v3v3(co, r_min, r_max);
        }
-       ccgVertIterator_free(vi);
 
-       for (ei = ccgSubSurf_getEdgeIterator(ss); 
!ccgEdgeIterator_isStopped(ei); ccgEdgeIterator_next(ei)) {
-               CCGEdge *e = ccgEdgeIterator_getCurrent(ei);
+       for (ccgSubSurf_initEdgeIterator(ss, &ei); 
!ccgEdgeIterator_isStopped(&ei); ccgEdgeIterator_next(&ei)) {
+               CCGEdge *e = ccgEdgeIterator_getCurrent(&ei);
                CCGElem *edgeData = ccgSubSurf_getEdgeDataArray(ss, e);
 
                for (i = 0; i < edgeSize; i++)
                        minmax_v3_v3v3(CCG_elem_offset_co(&key, edgeData, i), 
r_min, r_max);
        }
-       ccgEdgeIterator_free(ei);
 
-       for (fi = ccgSubSurf_getFaceIterator(ss); 
!ccgFaceIterator_isStopped(fi); ccgFaceIterator_next(fi)) {
-               CCGFace *f = ccgFaceIterator_getCurrent(fi);
+       for (ccgSubSurf_initFaceIterator(ss, &fi); 
!ccgFaceIterator_isStopped(&fi); ccgFaceIterator_next(&fi)) {
+               CCGFace *f = ccgFaceIterator_getCurrent(&fi);
                int S, x, y, numVerts = ccgSubSurf_getFaceNumVerts(f);
 
                for (S = 0; S < numVerts; S++) {
@@ -736,7 +733,6 @@ static void ccgDM_getMinMax(DerivedMesh *dm, float 
r_min[3], float r_max[3])
                                        minmax_v3_v3v3(CCG_grid_elem_co(&key, 
faceGridData, x, y), r_min, r_max);
                }
        }
-       ccgFaceIterator_free(fi);
 }
 
 static int ccgDM_getNumVerts(DerivedMesh *dm)
@@ -1429,9 +1425,9 @@ static void ccgdm_getVertCos(DerivedMesh *dm, float 
(*cos)[3])
        int edgeSize = ccgSubSurf_getEdgeSize(ss);
        int gridSize = ccgSubSurf_getGridSize(ss);
        int i;
-       CCGVertIterator *vi;
-       CCGEdgeIterator *ei;
-       CCGFaceIterator *fi;
+       CCGVertIterator vi;
+       CCGEdgeIterator ei;
+       CCGFaceIterator fi;
        CCGFace **faceMap2;
        CCGEdge **edgeMap2;
        CCGVert **vertMap2;
@@ -1439,30 +1435,27 @@ static void ccgdm_getVertCos(DerivedMesh *dm, float 
(*cos)[3])
        
        totvert = ccgSubSurf_getNumVerts(ss);
        vertMap2 = MEM_mallocN(totvert * sizeof(*vertMap2), "vertmap");
-       for (vi = ccgSubSurf_getVertIterator(ss); 
!ccgVertIterator_isStopped(vi); ccgVertIterator_next(vi)) {
-               CCGVert *v = ccgVertIterator_getCurrent(vi);
+       for (ccgSubSurf_initVertIterator(ss, &vi); 
!ccgVertIterator_isStopped(&vi); ccgVertIterator_next(&vi)) {
+               CCGVert *v = ccgVertIterator_getCurrent(&vi);
 
                vertMap2[GET_INT_FROM_POINTER(ccgSubSurf_getVertVertHandle(v))] 
= v;
        }
-       ccgVertIterator_free(vi);
 
        totedge = ccgSubSurf_getNumEdges(ss);
        edgeMap2 = MEM_mallocN(totedge * sizeof(*edgeMap2), "edgemap");
-       for (ei = ccgSubSurf_getEdgeIterator(ss), i = 0; 
!ccgEdgeIterator_isStopped(ei); i++, ccgEdgeIterator_next(ei)) {
-               CCGEdge *e = ccgEdgeIterator_getCurrent(ei);
+       for (ccgSubSurf_initEdgeIterator(ss, &ei), i = 0; 
!ccgEdgeIterator_isStopped(&ei); i++, ccgEdgeIterator_next(&ei)) {
+               CCGEdge *e = ccgEdgeIterator_getCurrent(&ei);
 
                edgeMap2[GET_INT_FROM_POINTER(ccgSubSurf_getEdgeEdgeHandle(e))] 
= e;
        }
-       ccgEdgeIterator_free(ei);
 
        totface = ccgSubSurf_getNumFaces(ss);
        faceMap2 = MEM_mallocN(totface * sizeof(*faceMap2), "facemap");
-       for (fi = ccgSubSurf_getFaceIterator(ss); 
!ccgFaceIterator_isStopped(fi); ccgFaceIterator_next(fi)) 

@@ Diff output truncated at 10240 characters. @@

_______________________________________________
Bf-blender-cvs mailing list
[email protected]
http://lists.blender.org/mailman/listinfo/bf-blender-cvs

Reply via email to