hi,
in my previous longish post I reported that sending self-destruction
messages to a canvas (menuclose' orcut') 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 casesabc1' and ab1', and also inab2' case (bindlist annihilation). After applying lookahead
safeguard from my previous post, Pd will crash in cases abc2' andab2' (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)