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.
#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;
--- 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;
} t_bindelem;
typedef struct _bindlist { t_pd b_pd; t_bindelem *b_list;
} t_bindlist;
+#define bindelem_lock(x) ((x)->e_locked = 1)
+/* Return 1 if a not visited object is being left after bindlist annihilation,
+*/ +static int bindelem_unlock(t_bindelem **x, t_symbol *s) +{
/* symbol has no bindings, iff we were unbound as the last object */
/* bindlist is gone, iff we hold the last remaining object */
/* there is at least one other object bound */
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 */
}
+}
static void bindlist_bang(t_bindlist *x) { t_bindelem *e = x->b_list; -#if CRASHY /* the loop we have now */
pd_bang(e->e_who);
-#else /* safer loop */
pd_bang(who);
pd_bang(e->e_who);
-#endif }
static void bindlist_float(t_bindlist *x, t_float f) { t_bindelem *e = x->b_list; -#if 1 /* the loop we have now */
pd_float(e->e_who, f);
-#else /* safer loop */
pd_float(who, f);
pd_float(e->e_who, f);
-#endif }
static void bindlist_symbol(t_bindlist *x, t_symbol *s) {
}
static void bindlist_pointer(t_bindlist *x, t_gpointer *gp) {
}
static void bindlist_list(t_bindlist *x, t_symbol *s, int argc, t_atom *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 */
pd_typedmess(e->e_who, s, argc, argv);
-#else /* safer loop */
pd_typedmess(who, s, argc, argv);
pd_typedmess(e->e_who, 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)