From 98203198b6aacbeb99f1e10a9f41acaa9ead0126 Mon Sep 17 00:00:00 2001 From: wm4 Date: Mon, 24 Oct 2011 02:28:56 +0200 Subject: input: fix crashes with libmenu Note: now that libmenu has been removed, the related code in input.c has been removed. If libmenu is ever added back, a queue_remove() function that can remove any item in the input queue will be required. libmenu triggered some special case that caused crashes by double frees. In particular the queue_pop function is used, expecting to remove an element that is not necessarily always the one that queue_pop removes. Fix by adding a queue_remove functions. Rewrite the other queue functions, since these are probably buggy as well. queue_pop didn't even attempt to maintain the doubly linked list. --- input/input.c | 49 +++++++++++++++++++++++++++++++++---------------- input/input.h | 1 - 2 files changed, 33 insertions(+), 17 deletions(-) (limited to 'input') diff --git a/input/input.c b/input/input.c index e1c001077a..c81a9f1d16 100644 --- a/input/input.c +++ b/input/input.c @@ -571,7 +571,6 @@ struct cmd_bind_section { struct cmd_queue { struct mp_cmd *first; - struct mp_cmd *last; int num_cmds; int num_abort_cmds; }; @@ -693,32 +692,50 @@ static bool is_abort_cmd(int cmd_id) return false; } -static void queue_pop(struct cmd_queue *queue) +// members updated by this should be replaced by functions +static void queue_internal_update(struct cmd_queue *queue) { - assert(queue->num_cmds > 0); + queue->num_cmds = 0; + queue->num_abort_cmds = 0; struct mp_cmd *cmd = queue->first; - queue->first = cmd->queue_next; - queue->num_cmds--; - queue->num_abort_cmds -= is_abort_cmd(cmd->id); + while (cmd) { + queue->num_cmds++; + queue->num_abort_cmds += is_abort_cmd(cmd->id); + cmd = cmd->queue_next; + } +} + +static void queue_remove(struct cmd_queue *queue, struct mp_cmd *cmd) +{ + struct mp_cmd **p_prev = &queue->first; + while (*p_prev != cmd) { + p_prev = &(*p_prev)->queue_next; + } + // if this fails, cmd was not in the queue + assert(*p_prev == cmd); + *p_prev = cmd->queue_next; + queue_internal_update(queue); +} + +static void queue_pop(struct cmd_queue *queue) +{ + queue_remove(queue, queue->first); } static void queue_add(struct cmd_queue *queue, struct mp_cmd *cmd, bool at_head) { - if (!queue->num_cmds) { - queue->first = cmd; - queue->last = cmd; - } else if (at_head) { - queue->first->queue_prev = cmd; + if (at_head) { cmd->queue_next = queue->first; queue->first = cmd; } else { - queue->last->queue_next = cmd; - cmd->queue_prev = queue->last; - queue->last = cmd; + struct mp_cmd **p_prev = &queue->first; + while (*p_prev) + p_prev = &(*p_prev)->queue_next; + *p_prev = cmd; + cmd->queue_next = NULL; } - queue->num_cmds++; - queue->num_abort_cmds += is_abort_cmd(cmd->id); + queue_internal_update(queue); } int mp_input_add_cmd_fd(struct input_ctx *ictx, int fd, int select, diff --git a/input/input.h b/input/input.h index 4058ce3d99..8d32a9907c 100644 --- a/input/input.h +++ b/input/input.h @@ -194,7 +194,6 @@ typedef struct mp_cmd { int nargs; struct mp_cmd_arg args[MP_CMD_MAX_ARGS]; int pausing; - struct mp_cmd *queue_prev; struct mp_cmd *queue_next; } mp_cmd_t; -- cgit v1.2.3