From 78a175dcb6522f294858c01616ffdde47da56c0c Mon Sep 17 00:00:00 2001 From: Jonathan Wilkes <jon.w.wilkes@gmail.com> Date: Sun, 10 Dec 2017 00:59:22 -0500 Subject: [PATCH] protect against a divide-by-zero, set up event callbacks to work with nested ds arrays --- pd/src/g_template.c | 104 +++++++++++++++++++++++++++++++------------- 1 file changed, 73 insertions(+), 31 deletions(-) diff --git a/pd/src/g_template.c b/pd/src/g_template.c index 04cafa17d..e0251cbb1 100644 --- a/pd/src/g_template.c +++ b/pd/src/g_template.c @@ -1738,8 +1738,15 @@ void svg_sendupdate(t_svg *x, t_canvas *c, t_symbol *s, need to experiment with gop scalars to make sure I'm not breaking anything */ char tag[MAXPDSTRING]; - int index = (array ? - ((((char *)data) - array->a_vec) / array->a_elemsize) : -1); + int index; + if (array) + { + int elemsize = array->a_elemsize; + if (!elemsize) elemsize = 1; + index = (((char *)data) - array->a_vec) / elemsize; + } + else + index = -1; if (x->x_type == gensym("g") || x->x_type == gensym("svg")) { sprintf(tag, "dgroup%lx.%lx", @@ -2135,7 +2142,22 @@ void svg_register_events(t_gobj *z, t_canvas *c, t_scalar *sc, t_template *template, t_word *data, t_array *a) { t_svg *svg; - int index = (a ? ((((char *)data) - a->a_vec) / a->a_elemsize) : -1); + int index; + if (a) + { + int elemsize = a->a_elemsize; + /* avoid divide-by-zero in case our elemsize is 0. Currently + there's no practical use case for an array of elements which + have zero size as there's no way to differentiate their + visualization. However if [draw array] changes in the future + to allow spacing out element groups or something like that, + we will have to revisit this workaround we're using to get + the element's index. */ + if (!elemsize) elemsize = 1; + index = (((char *)data) - a->a_vec) / elemsize; + } + else + index = -1; char tagbuf[MAXPDSTRING]; if (pd_class(&z->g_pd) == canvas_class) { @@ -4463,35 +4485,42 @@ static int draw_click(t_gobj *z, t_glist *glist, But the one person I know who uses nested ds arrays hasn't asked for that, so let's see if we can just make it to the end of this software's life before that happens. */ -static void scalar_spelunkforword(t_scalar *x, t_symbol *s, int word_index, - t_array **array, t_word **data) -{ - /* from glob_findinstance */ - long obj = 0; - if (sscanf(s->s_name, "x%lx", &obj)) - { - t_template *template = template_findbyname(x->sc_template); - if (!template) - { - pd_error(x, "scalar: template disappeared before notification " - "from gui arrived"); +static void scalar_spelunkforword(void* word_candidate, t_template* template, + t_word *data, int word_index, t_array **arrayp, t_word **datap) +{ + int i, nitems = template->t_n; + t_dataslot *datatypes = template->t_vec; + t_word *wp = data; + for (i = 0; i < nitems; i++, datatypes++, wp++) + { + if (datatypes->ds_type == DT_ARRAY && + ((void *)wp->w_array) == (void *)word_candidate) + { + /* Make sure we're in range, as the array could have been + resized. In that case simply return */ + if (word_index >= wp->w_array->a_n) return; + *arrayp = wp->w_array; + *datap = ((t_word *)(wp->w_array->a_vec + + word_index * wp->w_array->a_elemsize)); return; } - int i, nitems = template->t_n; - t_dataslot *datatypes = template->t_vec; - t_word *wp = x->sc_vec; - for (i = 0; i < nitems; i++, datatypes++, wp++) + } + /* Now swoop through the headers again and recursively search + any arrays for nested data. We do this as a second step so + that toplevel arrays don't take a performance hit from deeply + nested arrays. (Probably not a big deal for click events, but + for complex data structures it could be noticeable for drag + events */ + wp = data; + datatypes = template->t_vec; + for (i = 0; i < nitems; i++, datatypes++, wp++) + if (datatypes->ds_type == DT_ARRAY) { - if (datatypes->ds_type == DT_ARRAY && - ((void *)wp->w_array) == (void *)obj && - word_index < wp->w_array->a_n) - { - *array = wp->w_array; - *data = ((t_word *)(wp->w_array->a_vec + - word_index * wp->w_array->a_elemsize)); - } + t_template* t = template_findbyname(wp->w_array->a_templatesym); + if (t) + scalar_spelunkforword(word_candidate, t, + (t_word *)wp->w_array->a_vec, word_index, arrayp, datap); } - } } void draw_notify(t_canvas *x, t_symbol *s, int argc, t_atom *argv) @@ -4519,11 +4548,24 @@ void draw_notify(t_canvas *x, t_symbol *s, int argc, t_atom *argv) or greater then that's what we have */ if (index > -1) { - scalar_spelunkforword(sc, array_sym, index, &a, &data); + t_template *template = template_findbyname(sc->sc_template); + if (!template) + { + pd_error(sc, "scalar: template disappeared before notification " + "from gui arrived"); + return; + } + long word_candidate = 0; /* from glob_findinstance */ + if (!sscanf(array_sym->s_name, "x%lx", &word_candidate)) + { + pd_error(sc, "scalar: couldn't read array datum from GUI"); + return; + } + scalar_spelunkforword((void *)word_candidate, template, sc->sc_vec, + index, &a, &data); if (!data) { - pd_error(x, "scalar: couldn't get array data for event " - "callback"); + pd_error(x, "scalar: couldn't get array data for event callback"); return; } } -- GitLab