summaryrefslogtreecommitdiffstats
path: root/player
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2014-08-31 19:51:41 +0200
committerwm4 <wm4@nowhere>2014-08-31 19:51:41 +0200
commitf59f1e532e46779b1758bedf972fdfce3a74ea44 (patch)
tree39a6f6f6b4b7bb655aafe37c7ec6c3b52a1b3abd /player
parent866e0e1670f79653203a3da65096841ab37fc903 (diff)
downloadmpv-f59f1e532e46779b1758bedf972fdfce3a74ea44.tar.bz2
mpv-f59f1e532e46779b1758bedf972fdfce3a74ea44.tar.xz
client API: fix memory leak with rejected events
The event was copied early, and wasn't released if it was rejected instead of being added to the event queue. Fix by copying the event at a point when it's certainly added to the event queue. The dup_event_data() function is merely moved.
Diffstat (limited to 'player')
-rw-r--r--player/client.c71
1 files changed, 36 insertions, 35 deletions
diff --git a/player/client.c b/player/client.c
index 411d634100..f1e824fc5d 100644
--- a/player/client.c
+++ b/player/client.c
@@ -416,6 +416,32 @@ int mpv_initialize(mpv_handle *ctx)
return 0;
}
+// set ev->data to a new copy of the original data
+// (done only for message types that are broadcast)
+static void dup_event_data(struct mpv_event *ev)
+{
+ switch (ev->event_id) {
+ case MPV_EVENT_CLIENT_MESSAGE: {
+ struct mpv_event_client_message *src = ev->data;
+ struct mpv_event_client_message *msg =
+ talloc_zero(NULL, struct mpv_event_client_message);
+ for (int n = 0; n < src->num_args; n++) {
+ MP_TARRAY_APPEND(msg, msg->args, msg->num_args,
+ talloc_strdup(msg, src->args[n]));
+ }
+ ev->data = msg;
+ break;
+ }
+ case MPV_EVENT_END_FILE:
+ ev->data = talloc_memdup(NULL, ev->data, sizeof(mpv_event_end_file));
+ break;
+ default:
+ // Doesn't use events with memory allocation.
+ if (ev->data)
+ abort();
+ }
+}
+
// Reserve an entry in the ring buffer. This can be used to guarantee that the
// reply can be made, even if the buffer becomes congested _after_ sending
// the request.
@@ -432,17 +458,19 @@ static int reserve_reply(struct mpv_handle *ctx)
return res;
}
-static int append_event(struct mpv_handle *ctx, struct mpv_event *event)
+static int append_event(struct mpv_handle *ctx, struct mpv_event event, bool copy)
{
if (ctx->num_events + ctx->reserved_events >= ctx->max_events)
return -1;
- ctx->events[(ctx->first_event + ctx->num_events) % ctx->max_events] = *event;
+ if (copy)
+ dup_event_data(&event);
+ ctx->events[(ctx->first_event + ctx->num_events) % ctx->max_events] = event;
ctx->num_events++;
wakeup_client(ctx);
return 0;
}
-static int send_event(struct mpv_handle *ctx, struct mpv_event *event)
+static int send_event(struct mpv_handle *ctx, struct mpv_event *event, bool copy)
{
pthread_mutex_lock(&ctx->lock);
uint64_t mask = 1ULL << event->event_id;
@@ -452,7 +480,7 @@ static int send_event(struct mpv_handle *ctx, struct mpv_event *event)
pthread_mutex_unlock(&ctx->lock);
return 0;
}
- int r = append_event(ctx, event);
+ int r = append_event(ctx, *event, copy);
if (r < 0 && !ctx->choke_warning) {
mp_err(ctx->log, "Too many events queued.\n");
ctx->choke_warning = true;
@@ -471,8 +499,8 @@ static void send_reply(struct mpv_handle *ctx, uint64_t userdata,
// If this fails, reserve_reply() probably wasn't called.
assert(ctx->reserved_events > 0);
ctx->reserved_events--;
- if (append_event(ctx, event) < 0)
- abort();
+ if (append_event(ctx, *event, false) < 0)
+ abort(); // not reached
pthread_mutex_unlock(&ctx->lock);
}
@@ -486,32 +514,6 @@ static void status_reply(struct mpv_handle *ctx, int event,
send_reply(ctx, userdata, &reply);
}
-// set ev->data to a new copy of the original data
-// (done only for message types that are broadcast)
-static void dup_event_data(struct mpv_event *ev)
-{
- switch (ev->event_id) {
- case MPV_EVENT_CLIENT_MESSAGE: {
- struct mpv_event_client_message *src = ev->data;
- struct mpv_event_client_message *msg =
- talloc_zero(NULL, struct mpv_event_client_message);
- for (int n = 0; n < src->num_args; n++) {
- MP_TARRAY_APPEND(msg, msg->args, msg->num_args,
- talloc_strdup(msg, src->args[n]));
- }
- ev->data = msg;
- break;
- }
- case MPV_EVENT_END_FILE:
- ev->data = talloc_memdup(NULL, ev->data, sizeof(mpv_event_end_file));
- break;
- default:
- // Doesn't use events with memory allocation.
- if (ev->data)
- abort();
- }
-}
-
// Return whether there's any client listening to this event.
// If false is returned, the core doesn't need to send it.
bool mp_client_event_is_registered(struct MPContext *mpctx, int event)
@@ -546,8 +548,7 @@ void mp_client_broadcast_event(struct MPContext *mpctx, int event, void *data)
.event_id = event,
.data = data,
};
- dup_event_data(&event_data);
- send_event(clients->clients[n], &event_data);
+ send_event(clients->clients[n], &event_data, true);
}
pthread_mutex_unlock(&clients->lock);
@@ -568,7 +569,7 @@ int mp_client_send_event(struct MPContext *mpctx, const char *client_name,
struct mpv_handle *ctx = find_client(clients, client_name);
if (ctx) {
- r = send_event(ctx, &event_data);
+ r = send_event(ctx, &event_data, false);
} else {
r = -1;
talloc_free(data);