[PD] [devel] more bindlist-related crashes (was: self-destruction)
Krzysztof Czaja
czaja at chopin.edu.pl
Thu Dec 27 13:11:02 CET 2001
hi,
in my previous longish post I reported that sending self-destruction
messages to a canvas (`menuclose' or `cut') may prove deadly. This
`misfeature', if taken on its own, is not important -- after all,
hacking has a price, ``one gets what one asked for'', etc.
But there is another weak spot -- receive symbol of gui objects.
This symbol may be changed via `receive' message, and in certain ways
such a change may easily crash Pd: during bindlist traversal any
bindlist element may send a message causing unfortunate modification
of its bindlist, i.e. leaving a fatal dangling pointer.
To prove the point, here is an attached test patch `gui-crashes.pd',
which crashes Pd in self-unbinding cases `abc1' and `ab1', and also
in `ab2' case (bindlist annihilation). After applying lookahead
safeguard from my previous post, Pd will crash in cases `abc2' and
`ab2' (next element unbinding).
While self-destruction related crashes may be avoided easily, there
are no simple safeguards against arbitrary un/rebinding of objects.
One quite elaborate (and costly) solution is to use some kind of
a locking strategy. An example of how to lock current bindlist
element is attached in `m_pd.c.diff'.
Another standard solution is to use `smart' pointers.
Yet another solution is to get rid of (or at least to warn against)
any message being a potential bindlist modifier.
Krzysztof
Btw. ``if (glist_isvisible())'' tests are missing before redraw
commands in iemgui_send/receive() of 0.35test4.
-------------- next part --------------
#N canvas 240 51 439 297 12;
#X msg 64 35 abc1;
#X msg 190 35 abc2;
#X msg 316 35 abc3;
#X msg 133 165 ab1;
#X msg 267 165 ab2;
#N canvas 0 0 523 344 abc1 0;
#X obj 226 21 inlet;
#X obj 226 62 symbol;
#X msg 226 102 receive empty \, receive \$1 \; \$1 bang;
#X obj 226 157 t a a a a;
#X obj 26 216 bng 30 250 50 0 empty empty empty 20 8 64 8 -262144 -1
-1;
#X obj 156 216 bng 30 250 50 0 empty empty empty 20 8 64 8 -262144 -1 -1
;
#X obj 276 216 bng 30 250 50 0 empty empty empty 20 8 64 8 -262144 -1
-1;
#X obj 26 266 print one;
#X obj 156 295 print two;
#X obj 276 266 print three;
#X msg 81 102 receive empty;
#X obj 402 225 print abc1;
#X connect 0 0 1 0;
#X connect 1 0 2 0;
#X connect 2 0 3 0;
#X connect 3 0 4 0;
#X connect 3 1 5 0;
#X connect 3 2 6 0;
#X connect 3 3 11 0;
#X connect 4 0 10 0;
#X connect 4 0 7 0;
#X connect 5 0 8 0;
#X connect 6 0 9 0;
#X connect 10 0 4 0;
#X restore 64 90 pd abc1;
#N canvas 0 0 523 344 abc2 0;
#X obj 226 21 inlet;
#X obj 226 62 symbol;
#X msg 226 102 receive empty \, receive \$1 \; \$1 bang;
#X obj 226 157 t a a a a;
#X obj 26 216 bng 30 250 50 0 empty empty empty 20 8 64 8 -262144 -1
-1;
#X obj 156 216 bng 30 250 50 0 empty empty empty 20 8 64 8 -262144 -1 -1
;
#X obj 276 216 bng 30 250 50 0 empty epmty empty 20 8 64 8 -262144 -1
-1;
#X obj 26 266 print one;
#X obj 156 295 print two;
#X obj 276 266 print three;
#X obj 402 225 print abc2;
#X msg 81 102 receive empty;
#X connect 0 0 1 0;
#X connect 1 0 2 0;
#X connect 2 0 3 0;
#X connect 3 0 4 0;
#X connect 3 1 5 0;
#X connect 3 2 6 0;
#X connect 3 3 10 0;
#X connect 4 0 11 0;
#X connect 4 0 7 0;
#X connect 5 0 8 0;
#X connect 6 0 9 0;
#X connect 11 0 5 0;
#X restore 190 90 pd abc2;
#N canvas 0 0 523 344 abc3 0;
#X obj 226 21 inlet;
#X obj 226 62 symbol;
#X msg 226 102 receive empty \, receive \$1 \; \$1 bang;
#X obj 226 157 t a a a a;
#X obj 26 216 bng 30 250 50 0 empty empty empty 20 8 64 8 -262144 -1
-1;
#X obj 156 216 bng 30 250 50 0 empty empty empty 20 8 64 8 -262144 -1 -1
;
#X obj 276 216 bng 30 250 50 0 empty empty empty 20 8 64 8 -262144 -1
-1;
#X obj 26 266 print one;
#X obj 156 295 print two;
#X obj 276 266 print three;
#X msg 81 102 receive empty;
#X obj 402 225 print abc3;
#X connect 0 0 1 0;
#X connect 1 0 2 0;
#X connect 2 0 3 0;
#X connect 3 0 4 0;
#X connect 3 1 5 0;
#X connect 3 2 6 0;
#X connect 3 3 11 0;
#X connect 4 0 10 0;
#X connect 4 0 7 0;
#X connect 5 0 8 0;
#X connect 6 0 9 0;
#X connect 10 0 6 0;
#X restore 316 90 pd abc3;
#N canvas 0 0 523 344 ab1 0;
#X obj 226 21 inlet;
#X obj 226 62 symbol;
#X msg 226 102 receive empty \, receive \$1 \; \$1 bang;
#X obj 26 216 bng 30 250 50 0 empty empty empty 20 8 64 8 -262144 -1
-1;
#X obj 156 216 bng 30 250 50 0 empty empty empty 20 8 64 8 -262144 -1 -1
;
#X obj 26 266 print one;
#X obj 156 295 print two;
#X msg 81 102 receive empty;
#X obj 298 216 print ab1;
#X obj 226 157 t a a a;
#X connect 0 0 1 0;
#X connect 1 0 2 0;
#X connect 2 0 9 0;
#X connect 3 0 7 0;
#X connect 3 0 5 0;
#X connect 4 0 6 0;
#X connect 7 0 3 0;
#X connect 9 0 3 0;
#X connect 9 1 4 0;
#X connect 9 2 8 0;
#X restore 133 221 pd ab1;
#N canvas 0 0 523 344 ab2 0;
#X obj 226 21 inlet;
#X obj 226 62 symbol;
#X msg 226 102 receive empty \, receive \$1 \; \$1 bang;
#X obj 26 216 bng 30 250 50 0 empty empty empty 20 8 64 8 -262144 -1
-1;
#X obj 156 216 bng 30 250 50 0 empty empty empty 20 8 64 8 -262144 -1 -1
;
#X obj 26 266 print one;
#X obj 156 295 print two;
#X msg 81 102 receive empty;
#X obj 226 157 t a a a;
#X obj 298 216 print ab2;
#X connect 0 0 1 0;
#X connect 1 0 2 0;
#X connect 2 0 8 0;
#X connect 3 0 7 0;
#X connect 3 0 5 0;
#X connect 4 0 6 0;
#X connect 7 0 4 0;
#X connect 8 0 3 0;
#X connect 8 1 4 0;
#X connect 8 2 9 0;
#X restore 267 221 pd ab2;
#X connect 0 0 5 0;
#X connect 1 0 6 0;
#X connect 2 0 7 0;
#X connect 3 0 8 0;
#X connect 4 0 9 0;
-------------- next part --------------
--- m_pd-orig.c Fri Dec 21 11:04:52 2001
+++ m_pd.c Thu Dec 27 12:57:57 2001
@@ -46,83 +46,121 @@
{
t_pd *e_who;
struct _bindelem *e_next;
+ int e_locked:1;
+ int e_freed:1;
} t_bindelem;
typedef struct _bindlist
{
t_pd b_pd;
t_bindelem *b_list;
+ t_symbol *b_symbol;
} t_bindlist;
+#define bindelem_lock(x) ((x)->e_locked = 1)
+
+/* Return 1 if a not visited object is being left after bindlist annihilation,
+ otherwise return 0. First argument upon return holds a pointer to next
+ element in a possibly modified bindlist (or null).
+*/
+static int bindelem_unlock(t_bindelem **x, t_symbol *s)
+{
+ /* symbol has no bindings, iff we were unbound as the last object */
+ if (s->s_thing
+ /* bindlist is gone, iff we hold the last remaining object */
+ && *s->s_thing == bindlist_class)
+ {
+ /* there is at least one other object bound */
+ t_bindelem *x1 = (*x)->e_next;
+ (*x)->e_locked = 0;
+ if ((*x)->e_freed)
+ {
+ pd_unbind((*x)->e_who, s);
+ if (*s->s_thing == bindlist_class) *x = x1;
+ else if (x1)
+ {
+ *x = 0;
+ return (1); /* the only remaining object was not visited yet */
+ }
+ }
+ else *x = x1;
+ }
+ else *x = 0;
+ return (0);
+}
+
static void bindlist_bang(t_bindlist *x)
{
t_bindelem *e = x->b_list;
-#if CRASHY /* the loop we have now */
- for (e = x->b_list; e; e = e->e_next)
- pd_bang(e->e_who);
-#else /* safer loop */
+ t_symbol *t = x->b_symbol;
while (e)
{
- t_pd *who = e->e_who;
- e = e->e_next;
- pd_bang(who);
+ bindelem_lock(e);
+ pd_bang(e->e_who);
+ if (bindelem_unlock(&e, t)) pd_bang(t->s_thing);
}
-#endif
}
static void bindlist_float(t_bindlist *x, t_float f)
{
t_bindelem *e = x->b_list;
-#if 1 /* the loop we have now */
- for (e = x->b_list; e; e = e->e_next)
- pd_float(e->e_who, f);
-#else /* safer loop */
+ t_symbol *t = x->b_symbol;
while (e)
{
- t_pd *who = e->e_who;
- e = e->e_next;
- pd_float(who, f);
+ bindelem_lock(e);
+ pd_float(e->e_who, f);
+ if (bindelem_unlock(&e, t)) pd_float(t->s_thing, f);
}
-#endif
}
static void bindlist_symbol(t_bindlist *x, t_symbol *s)
{
- t_bindelem *e;
- for (e = x->b_list; e; e = e->e_next)
+ t_bindelem *e = x->b_list;
+ t_symbol *t = x->b_symbol;
+ while (e)
+ {
+ bindelem_lock(e);
pd_symbol(e->e_who, s);
+ if (bindelem_unlock(&e, t)) pd_symbol(t->s_thing, s);
+ }
}
static void bindlist_pointer(t_bindlist *x, t_gpointer *gp)
{
- t_bindelem *e;
- for (e = x->b_list; e; e = e->e_next)
+ t_bindelem *e = x->b_list;
+ t_symbol *t = x->b_symbol;
+ while (e)
+ {
+ bindelem_lock(e);
pd_pointer(e->e_who, gp);
+ if (bindelem_unlock(&e, t)) pd_pointer(t->s_thing, gp);
+ }
}
static void bindlist_list(t_bindlist *x, t_symbol *s,
int argc, t_atom *argv)
{
- t_bindelem *e;
- for (e = x->b_list; e; e = e->e_next)
+ t_bindelem *e = x->b_list;
+ t_symbol *t = x->b_symbol;
+ while (e)
+ {
+ bindelem_lock(e);
pd_list(e->e_who, s, argc, argv);
+ if (bindelem_unlock(&e, t)) pd_list(t->s_thing, s, argc, argv);
+ }
}
static void bindlist_anything(t_bindlist *x, t_symbol *s,
int argc, t_atom *argv)
{
t_bindelem *e = x->b_list;
-#if CRASHY /* the loop we have now */
- for (e = x->b_list; e; e = e->e_next)
- pd_typedmess(e->e_who, s, argc, argv);
-#else /* safer loop */
+ t_symbol *t = x->b_symbol;
while (e)
{
- t_pd *who = e->e_who;
- e = e->e_next;
- pd_typedmess(who, s, argc, argv);
+ bindelem_lock(e);
+ pd_typedmess(e->e_who, s, argc, argv);
+ if (bindelem_unlock(&e, t)) pd_typedmess(t->s_thing, s, argc, argv);
}
-#endif
}
void m_pd_setup(void)
@@ -147,6 +185,7 @@
t_bindelem *e = (t_bindelem *)getbytes(sizeof(t_bindelem));
e->e_next = b->b_list;
e->e_who = x;
+ e->e_locked = e->e_freed = 0;
b->b_list = e;
}
else
@@ -155,10 +194,13 @@
t_bindelem *e1 = (t_bindelem *)getbytes(sizeof(t_bindelem));
t_bindelem *e2 = (t_bindelem *)getbytes(sizeof(t_bindelem));
b->b_list = e1;
+ b->b_symbol = s;
e1->e_who = x;
e1->e_next = e2;
+ e1->e_locked = e1->e_freed = 0;
e2->e_who = s->s_thing;
e2->e_next = 0;
+ e2->e_locked = e2->e_freed = 0;
s->s_thing = &b->b_pd;
}
}
@@ -178,14 +220,22 @@
t_bindelem *e, *e2;
if ((e = b->b_list)->e_who == x)
{
- b->b_list = e->e_next;
- freebytes(e, sizeof(t_bindelem));
+ if (e->e_locked) e->e_freed = 1;
+ else
+ {
+ b->b_list = e->e_next;
+ freebytes(e, sizeof(t_bindelem));
+ }
}
else for (e = b->b_list; e2 = e->e_next; e = e2)
if (e2->e_who == x)
{
- e->e_next = e2->e_next;
- freebytes(e2, sizeof(t_bindelem));
+ if (e2->e_locked) e2->e_freed = 1;
+ else
+ {
+ e->e_next = e2->e_next;
+ freebytes(e2, sizeof(t_bindelem));
+ }
break;
}
if (!b->b_list->e_next)
More information about the Pd-list
mailing list