]> granicus.if.org Git - poly2tri-c/commitdiff
Solve bugs related to removing primitives from their free functions
authorBarak Itkin <lightningismyname@gmail.com>
Sat, 4 Aug 2012 16:45:07 +0000 (19:45 +0300)
committerBarak Itkin <lightningismyname@gmail.com>
Sat, 4 Aug 2012 16:45:07 +0000 (19:45 +0300)
poly2tri-c/refine/edge.c
poly2tri-c/refine/triangle.c

index bfbdbd355a0bd45b1571cd55a89d66e17270528f..a95a6eec3647f76eee5746ddd44c300e13e5b448 100644 (file)
@@ -72,8 +72,7 @@ p2tr_edge_new (P2trPoint *start,
   _p2tr_point_insert_edge (start, self);
   _p2tr_point_insert_edge (end,   mirror);
 
-  ++self->refcount;
-  return self;
+  return p2tr_edge_ref (self);
 }
 
 P2trEdge*
@@ -122,12 +121,28 @@ p2tr_edge_remove (P2trEdge *self)
       p2tr_mesh_unref (mesh); /* The get function reffed it */
     }
 
+  /* Warning - the code here is not that trivial!
+   * Assuming we would now want to remove `self' and `self->mirror' from
+   * `start' and `end'. If both have exactly one reference, then after
+   * removing the second, the edge struct will be freed before we can
+   * mark it as removed by setting the end points to be NULL! (Marking
+   * it as removed in that case, will be an access to unallocated
+   * memory).
+   * To solve this, we will hold a "ghost" reference to `self' to
+   * prevent freeing from happening until we are done modifying the
+   * struct.
+   */
+   p2tr_edge_ref (self);
+
   _p2tr_point_remove_edge(start, self);
   _p2tr_point_remove_edge(end, self->mirror);
 
   self->end = NULL;
   self->mirror->end = NULL;
 
+  /* Now release the "ghost" reference */
+  p2tr_edge_unref (self);
+
   p2tr_point_unref (start);
   p2tr_point_unref (end);
 }
@@ -135,7 +150,7 @@ p2tr_edge_remove (P2trEdge *self)
 void
 p2tr_edge_free (P2trEdge *self)
 {
-  p2tr_edge_remove (self);
+  g_assert (p2tr_edge_is_removed (self));
   g_slice_free (P2trEdge, self->mirror);
   g_slice_free (P2trEdge, self);
 }
@@ -162,19 +177,20 @@ p2tr_edge_get_mesh (P2trEdge *self)
 }
 
 gdouble
-p2tr_edge_get_length(P2trEdge* self)
+p2tr_edge_get_length (P2trEdge* self)
 {
   return sqrt (p2tr_math_length_sq2 (&self->end->c, &P2TR_EDGE_START(self)->c));
 }
 
 gdouble
-p2tr_edge_get_length_squared(P2trEdge* self)
+p2tr_edge_get_length_squared (P2trEdge* self)
 {
   return p2tr_math_length_sq2 (&self->end->c, &P2TR_EDGE_START(self)->c);
 }
 
 gdouble
-p2tr_edge_angle_between(P2trEdge *e1, P2trEdge *e2)
+p2tr_edge_angle_between (P2trEdge *e1,
+                         P2trEdge *e2)
 {
   /* A = E1.angle, a = abs (A)
    * B = E1.angle, b = abs (B)
@@ -220,7 +236,8 @@ p2tr_edge_angle_between(P2trEdge *e1, P2trEdge *e2)
 }
 
 gdouble
-p2tr_edge_angle_between_positive (P2trEdge *e1, P2trEdge *e2)
+p2tr_edge_angle_between_positive (P2trEdge *e1,
+                                  P2trEdge *e2)
 {
   gdouble result = p2tr_edge_angle_between (e1, e2);
   if (result < 0)
index 6e05713fa8763e9c12e1c2cce00634e72adc77d5..ce28dcc9356cd5d9520624896917ac7830e7f43f 100644 (file)
@@ -142,7 +142,7 @@ p2tr_triangle_unref (P2trTriangle *self)
 void
 p2tr_triangle_free (P2trTriangle *self)
 {
-  p2tr_triangle_remove (self);
+  g_assert (p2tr_triangle_is_removed (self));
   g_slice_free (P2trTriangle, self);
 }