(Widgets) Fix serious heap-use-after-free errors

This commit is contained in:
jdgleaver 2020-06-10 12:30:59 +01:00
parent c63a65ffa5
commit 9bbc9dd30e
3 changed files with 41 additions and 37 deletions

View File

@ -2246,12 +2246,19 @@ bool gfx_animation_kill_by_tag(uintptr_t *tag)
if (!tag || *tag == (uintptr_t)-1)
return false;
/* Scan animation list */
for (i = 0; i < da_count(p_anim->list); ++i)
{
struct tween *t = da_getptr(p_anim->list, i);
if (!t || t->tag != *tag)
continue;
/* If we are currently inside gfx_animation_update(),
* we are already looping over p_anim->list entries
* > Cannot modify p_anim->list now, so schedule a
* delete for when the gfx_animation_update() loop
* is complete */
if (p_anim->in_update)
{
t->deleted = true;
@ -2264,41 +2271,26 @@ bool gfx_animation_kill_by_tag(uintptr_t *tag)
}
}
return true;
}
void gfx_animation_kill_by_subject(gfx_animation_ctx_subject_t *subject)
{
unsigned i, j, killed = 0;
float **sub = (float**)subject->data;
gfx_animation_t *p_anim = anim_get_ptr();
for (i = 0; i < da_count(p_anim->list) && killed < subject->count; ++i)
/* If we are currently inside gfx_animation_update(),
* also have to scan *pending* animation list
* (otherwise any entries that are simultaneously added
* and deleted inside gfx_animation_update() won't get
* deleted at all, producing utter chaos) */
if (p_anim->in_update)
{
struct tween *t = da_getptr(p_anim->list, i);
if (!t)
continue;
for (j = 0; j < subject->count; ++j)
for (i = 0; i < da_count(p_anim->pending); ++i)
{
if (t->subject != sub[j])
struct tween *t = da_getptr(p_anim->pending, i);
if (!t || t->tag != *tag)
continue;
if (p_anim->in_update)
{
t->deleted = true;
p_anim->pending_deletes = true;
}
else
{
da_delete(p_anim->list, i);
--i;
}
killed++;
break;
da_delete(p_anim->pending, i);
--i;
}
}
return true;
}
float gfx_animation_get_delta_time(void)

View File

@ -100,12 +100,6 @@ enum gfx_animation_ticker_type
TICKER_TYPE_LAST
};
typedef struct gfx_animation_ctx_subject
{
size_t count;
const void *data;
} gfx_animation_ctx_subject_t;
typedef struct gfx_animation_ctx_entry
{
enum gfx_animation_easing_type easing_enum;
@ -219,8 +213,6 @@ bool gfx_animation_is_active(void);
bool gfx_animation_kill_by_tag(uintptr_t *tag);
void gfx_animation_kill_by_subject(gfx_animation_ctx_subject_t *subject);
bool gfx_animation_push(gfx_animation_ctx_entry_t *entry);
void gfx_animation_push_delayed(unsigned delay, gfx_animation_ctx_entry_t *entry);

View File

@ -2252,6 +2252,16 @@ static void gfx_widgets_free(dispgfx_widget_t *p_dispwidget)
fifo_read(p_dispwidget->msg_queue,
&msg_widget, sizeof(msg_widget));
/* Note: gfx_widgets_free() is only called when
* main_exit() is invoked. At this stage, we cannot
* guarantee that any task pointers are valid (the
* task may have been free()'d, but we can't know
* that here) - so all we can do is unset the task
* pointer associated with each message
* > If we don't do this, gfx_widgets_msg_queue_free()
* will generate heap-use-after-free errors */
msg_widget->task_ptr = NULL;
gfx_widgets_msg_queue_free(p_dispwidget, msg_widget, false);
free(msg_widget);
}
@ -2268,6 +2278,16 @@ static void gfx_widgets_free(dispgfx_widget_t *p_dispwidget)
menu_widget_msg_t *msg = (menu_widget_msg_t*)
p_dispwidget->current_msgs->list[i].userdata;
/* Note: gfx_widgets_free() is only called when
* main_exit() is invoked. At this stage, we cannot
* guarantee that any task pointers are valid (the
* task may have been free()'d, but we can't know
* that here) - so all we can do is unset the task
* pointer associated with each message
* > If we don't do this, gfx_widgets_msg_queue_free()
* will generate heap-use-after-free errors */
msg->task_ptr = NULL;
gfx_widgets_msg_queue_free(p_dispwidget, msg, false);
}
file_list_free(p_dispwidget->current_msgs);