Dear list, I found something that seems like a bug to me, but I’m still not sure, it could be something in my code. Could someone take a look and tell me if I’m doing something incorrectly?
The GUI object pasted below will sometimes crash on close when in a sub-patcher, but not in a top level patcher.
What is confusing to me is that the order of objects in the .pd file seems to make a difference.
On my system this patch crashes on close with a Segmentation Fault: 11:
#N canvas 627 164 450 300 10; #N canvas 546 160 450 300 foo 0; #X obj 117 115 basicgui; #X obj 126 56 inlet; #X connect 1 0 0 0; #X restore 131 90 pd foo;
But this version of the same exact patch with only the creation order of objects in the file changed, does *not* crash:
#N canvas 627 164 450 300 10; #N canvas 546 160 450 300 foo 0; #X obj 126 56 inlet; #X obj 117 115 basicgui; #X connect 0 0 1 0; #X restore 131 90 pd foo;
The crash log seems to point to a problem with the number of inlets while the linetraverser is running… but I’m not sure how to correct my code to avoid this.
Many thanks for any advice! Rama
MacOS 10.10.2 Pd 0.46.6
Crash log:
Exception Type: EXC_BAD_ACCESS (SIGSEGV) Exception Codes: EXC_I386_GPFLT
Thread 0 Crashed:: Dispatch queue: com.apple.main-thread 0 pd 0x0000000106e7f59c obj_ninlets + 76 1 pd 0x0000000106e29bb9 linetraverser_next + 569 2 pd 0x0000000106e2b232 canvas_deletelinesfor + 50 3 pd 0x0000000106e33fb5 text_delete + 37 4 pd 0x0000000106e504b7 gobj_delete + 87 5 pd 0x0000000106e2e485 glist_delete + 597 6 pd 0x0000000106e3168d graph_delete + 61 7 pd 0x0000000106e504b7 gobj_delete + 87 8 pd 0x0000000106e2e485 glist_delete + 597 9 pd 0x0000000106e2aefd canvas_free + 109 10 pd 0x0000000106e79d14 pd_free + 68 11 pd 0x0000000106e56869 canvas_menuclose + 265 12 pd 0x0000000106e7d07b pd_typedmess + 1515 13 pd 0x0000000106e4d6b1 guiconnect_anything + 65 14 pd 0x0000000106e7d23d pd_typedmess + 1965 15 pd 0x0000000106e839e7 binbuf_eval + 2215 16 pd 0x0000000106e8ef78 socketreceiver_read + 648 17 pd 0x0000000106e8e80d sys_domicrosleep + 557 18 pd 0x0000000106e8e5c8 sys_microsleep + 24 19 pd 0x0000000106e8ab89 m_pollingscheduler + 857 20 pd 0x0000000106e8a738 m_mainloop + 56 21 pd 0x0000000106e8b485 sys_main + 501 22 pd 0x0000000106e974e2 main + 34 23 libdyld.dylib 0x00007fff905975c9 start + 1
// basicgui.c object:
#include "m_pd.h" #include "g_canvas.h"
typedef struct _basicgui { t_object ob; t_glist *glist; char io_tag[256]; int height, width, exists;
} t_basicgui;
static t_class *basicgui_class; t_widgetbehavior basicgui_widget;
static void basicgui_getrect(t_gobj *z, t_glist *glist,int *xp1, int *yp1, int *xp2, int *yp2) { t_basicgui *x = (t_basicgui *)z;
*xp1 = text_xpix(&x->ob, glist); *yp1 = text_ypix(&x->ob, glist); *xp2 = *xp1 + x->width; *yp2 = *yp1 + x->height; x->glist = glist; }
static void basicgui_displace(t_gobj *z, t_glist *glist, int dx, int dy) { t_basicgui *x = (t_basicgui *)z; sys_vgui(".x%lx.c move %lxBOX %d %d\n", glist_getcanvas(glist), z, dx, dy ); x->ob.te_xpix += dx; x->ob.te_ypix += dy;
int x1, x2, y1, y2; basicgui_getrect(z, glist, &x1, &y1, &x2, &y2);
t_object *ob = pd_checkobject(&x->ob.te_pd); if (ob){ glist_drawiofor(glist, ob, 0, x->io_tag, x->ob.te_xpix, x->ob.te_ypix, x2, y2); canvas_fixlinesfor(glist, &x->ob); }
}
static void basicgui_select(t_gobj *z, t_glist *glist, int state) {}
static void basicgui_activate(t_gobj *z, t_glist *glist, int state) {}
static void basicgui_delete(t_gobj *z, t_glist *glist) { printf("%s %p \n", __FUNCTION__, z);
t_canvas *canvas = glist_getcanvas(glist);
if(canvas->gl_editor) { printf("%s deleting %p \n", __FUNCTION__, z); sys_vgui(".x%lx.c delete %lxBOX \n", glist_getcanvas(glist), z );
t_basicgui *x = (t_basicgui *)z; t_object *ob = pd_checkobject(&x->ob.te_pd); if(ob && glist_isvisible(glist)) { glist_eraseiofor(glist, ob, x->io_tag); canvas_deletelinesfor(canvas, ob); } }
}
void basicgui_drawElements(t_basicgui *x, t_gobj *z, t_glist *glist, int firstime) { int x1, x2, y1, y2; basicgui_getrect(z, glist, &x1, &y1, &x2, &y2); if(firstime) { sys_vgui(".x%lx.c create rectangle %d %d %d %d -outline "blue" -fill "" -tags %lxBOX \n", glist_getcanvas(glist), x1, y1, x2, y2, z); } else { if (glist_isvisible(glist)) sys_vgui(".x%lx.c coords %lxBOX %d %d %d %d \n", glist_getcanvas(glist), z, x1, y1, x2, y2); }
t_object *ob = pd_checkobject(&x->ob.te_pd); if (ob){ glist_drawiofor(glist, ob, firstime, x->io_tag, x1, y1, x2, y2); } if (firstime) /* raise cords over everything else */ sys_vgui(".x%lx.c raise cord\n", glist_getcanvas(glist));
x->exists = 1; }
void basicgui_vis(t_gobj *z, t_glist *glist, int state) { // printf("%p %s state %d glist %p canvas %p\n", (t_basicgui *)z, __func__, state, glist, glist_getcanvas(glist)); t_basicgui *x = (t_basicgui *)z;
if(state) { basicgui_drawElements(x, z, glist, state); } else { if(x->exists) { basicgui_delete(z, glist); x->exists = 0; } }
}
void basicgui_save(t_gobj *z, t_binbuf *b) { t_basicgui *x = (t_basicgui *)z; binbuf_addv(b, "ssiis;", gensym("#X"),gensym("obj"), (t_int)x->ob.te_xpix, (t_int)x->ob.te_ypix, gensym("basicgui"));
}
void basicgui_bang(t_basicgui *x) { int x1, x2, y1, y2; basicgui_getrect((t_gobj *)x, x->glist, &x1, &y1, &x2, &y2); post("%x %s x1 %d y1 %d x2 %d y2 %d", x, __func__, x1, y1, x2, y2); post("text pix x %d y %d", text_xpix(&x->ob, x->glist), text_ypix(&x->ob, x->glist)); }
void *basicgui_new(void) { t_basicgui *x = (t_basicgui *)pd_new(basicgui_class); if(x) { x->glist = (t_glist *)canvas_getcurrent(); x->height = 10; x->width = 30; sprintf(x->io_tag, "%lxIOTAG", (long)x); } return (void *)x; }
void basicgui_setup(void) {
basicgui_class = class_new(gensym("basicgui"), (t_newmethod)basicgui_new, 0, sizeof(t_basicgui), CLASS_DEFAULT, 0);
class_addbang(basicgui_class, basicgui_bang);
basicgui_widget.w_getrectfn = basicgui_getrect; basicgui_widget.w_displacefn = basicgui_displace; basicgui_widget.w_deletefn = basicgui_delete; basicgui_widget.w_visfn = basicgui_vis; basicgui_widget.w_selectfn = NULL; basicgui_widget.w_activatefn = NULL; basicgui_widget.w_clickfn = NULL;
class_setsavefn(basicgui_class, basicgui_save); class_setwidget(basicgui_class, &basicgui_widget); }
On 04/08/2015 05:55 AM, Rama Gottfried wrote:
Dear list, I found something that seems like a bug to me, but I’m still not sure, it could be something in my code. Could someone take a look and tell me if I’m doing something incorrectly?
The GUI object pasted below will sometimes crash on close when in a sub-patcher, but not in a top level patcher.
What is confusing to me is that the order of objects in the .pd file seems to make a difference.
On my system this patch crashes on close with a Segmentation Fault: 11:
here it doesn't crash, but gives me an "error: consistency check failed: drawline".
in any case, i think you should call `canvas_deletelinesfor()` unconditionally, even if the object is not visible. something like:
~~~ static void basicgui_delete(t_gobj *z, t_glist *glist) { printf("%s %p \n", __FUNCTION__, z);
t_canvas *canvas = glist_getcanvas(glist); t_basicgui *x = (t_basicgui *)z; t_object *ob = pd_checkobject(&x->ob.te_pd);
if(canvas->gl_editor) { sys_vgui(".x%lx.c delete %lxBOX \n", glist_getcanvas(glist), z ); } if(ob && glist_isvisible(glist)) { glist_eraseiofor(glist, ob, x->io_tag); } canvas_deletelinesfor(canvas, ob); } ~~~
mfsdr IOhannes
PS: for the future, could you *attach* your files rather than paste them inline? it makes it so much easier to try them out.
Hi IOhannes, thanks so much for taking a look — this fixed the sub-patcher crash and error message issue which is great, but now I have a similar issue on close when the sub-patcher is a GOP.
Could this also be due to something in my delete routine? I tried placing a check for glist->gl_isgraph before canvas_deletelinesfor() and list_eraseiofor(), but so far haven’t been able to avoid the crash.
attaching the current basicgui.c and a test patch below.
thanks again, Rama
On Apr 9, 2015, at 2:08 PM, IOhannes m zmölnig zmoelnig@iem.at wrote:
On 04/08/2015 05:55 AM, Rama Gottfried wrote:
Dear list, I found something that seems like a bug to me, but I’m still not sure, it could be something in my code. Could someone take a look and tell me if I’m doing something incorrectly?
The GUI object pasted below will sometimes crash on close when in a sub-patcher, but not in a top level patcher.
What is confusing to me is that the order of objects in the .pd file seems to make a difference.
On my system this patch crashes on close with a Segmentation Fault: 11:
here it doesn't crash, but gives me an "error: consistency check failed: drawline".
in any case, i think you should call `canvas_deletelinesfor()` unconditionally, even if the object is not visible. something like:
static void basicgui_delete(t_gobj *z, t_glist *glist) { printf("%s %p \n", __FUNCTION__, z); t_canvas *canvas = glist_getcanvas(glist); t_basicgui *x = (t_basicgui *)z; t_object *ob = pd_checkobject(&x->ob.te_pd); if(canvas->gl_editor) { sys_vgui(".x%lx.c delete %lxBOX \n", glist_getcanvas(glist), z ); } if(ob && glist_isvisible(glist)) { glist_eraseiofor(glist, ob, x->io_tag); } canvas_deletelinesfor(canvas, ob); }
mfsdr IOhannes
PS: for the future, could you *attach* your files rather than paste them inline? it makes it so much easier to try them out.
Pd-dev mailing list Pd-dev@lists.iem.at http://lists.puredata.info/listinfo/pd-dev
On 04/10/2015 12:08 AM, Rama Gottfried wrote:
I tried placing a check for glist->gl_isgraph before canvas_deletelinesfor() and list_eraseiofor(), but so far haven’t been able to avoid the crash.
well, since Pd doesn't have much documentation for writing externals, the best way is usually to look at existing (and working) externals and how they solved the issues at hand.
now i did a quick check (e.g. g_text.c and all iemguis which use g_all_guis.c), and all of them simply call: canvas_deletelinesfor(glist, (t_text*)z); with 'glist' and 'z' being passed to the delete function by Pd - no fancy glist_getcanvas() to convert the glist to it's displaying) canvas.
and indeed, changing your line: -canvas_deletelinesfor(canvas, ob); to +canvas_deletelinesfor(glist, (t_text*)z);
seems to fix all your problems.
fmsadr IOhannes
ok, great, thank you! yes, I see now that every call of the canvas_deletelinesfor() in the src folder is as you wrote below. I forget now what I was using for reference when I wrote this — very possibly it was from some random third party object. I’ll go through and check the other bits of the code to make sure it’s in line with the g_text and iemguis.
thanks again, rama
On Apr 11, 2015, at 12:53 PM, IOhannes m zmölnig zmoelnig@iem.at wrote:
On 04/10/2015 12:08 AM, Rama Gottfried wrote:
I tried placing a check for glist->gl_isgraph before canvas_deletelinesfor() and list_eraseiofor(), but so far haven’t been able to avoid the crash.
well, since Pd doesn't have much documentation for writing externals, the best way is usually to look at existing (and working) externals and how they solved the issues at hand.
now i did a quick check (e.g. g_text.c and all iemguis which use g_all_guis.c), and all of them simply call: canvas_deletelinesfor(glist, (t_text*)z); with 'glist' and 'z' being passed to the delete function by Pd - no fancy glist_getcanvas() to convert the glist to it's displaying) canvas.
and indeed, changing your line: -canvas_deletelinesfor(canvas, ob); to +canvas_deletelinesfor(glist, (t_text*)z);
seems to fix all your problems.
fmsadr IOhannes
Pd-dev mailing list Pd-dev@lists.iem.at http://lists.puredata.info/listinfo/pd-dev