summaryrefslogtreecommitdiffstats
path: root/input
diff options
context:
space:
mode:
authorwm4 <wm4@mplayer2.org>2011-10-24 02:28:56 +0200
committerwm4 <wm4@mplayer2.org>2012-01-18 02:52:34 +0100
commit98203198b6aacbeb99f1e10a9f41acaa9ead0126 (patch)
tree525178fab52936aba1ebc463f6812dc60d02bab9 /input
parent03ba61c3bf01367ff6c1c134ebe70f2e7ecbcae2 (diff)
downloadmpv-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.c49
-rw-r--r--input/input.h1
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;