mirror of
https://github.com/libretro/RetroArch
synced 2025-03-30 16:20:27 +00:00
(Widgets) Fix serious heap-use-after-free errors
This commit is contained in:
parent
c63a65ffa5
commit
9bbc9dd30e
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user