diff options
author | wm4 <wm4@mplayer2.org> | 2011-10-24 02:28:56 +0200 |
---|---|---|
committer | wm4 <wm4@mplayer2.org> | 2012-01-18 02:52:34 +0100 |
commit | 98203198b6aacbeb99f1e10a9f41acaa9ead0126 (patch) | |
tree | 525178fab52936aba1ebc463f6812dc60d02bab9 /input | |
parent | 03ba61c3bf01367ff6c1c134ebe70f2e7ecbcae2 (diff) | |
download | mpv-98203198b6aacbeb99f1e10a9f41acaa9ead0126.tar.bz2 mpv-98203198b6aacbeb99f1e10a9f41acaa9ead0126.tar.xz |
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.
Diffstat (limited to 'input')
-rw-r--r-- | input/input.c | 49 | ||||
-rw-r--r-- | input/input.h | 1 |
2 files changed, 33 insertions, 17 deletions
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; |