Browse Source

io: fix cleanup for websock I/O source data on cancellation

The websock code will create a GSource for tracking completion of the
handshake process, passing a QIOTask which is freed by the callback
when it completes, which means when a source is cancelled, nothing is
free'ing the task.

Switch to provide a data free callback to the GSource, which ensures
the QIOTask is always freed even when the main event callback never
fires.

Fixes: https://gitlab.com/qemu-project/qemu/-/issues/3114
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
master
Daniel P. Berrangé 7 months ago
parent
commit
9545c059f7
  1. 49
      io/channel-websock.c

49
io/channel-websock.c

@ -526,11 +526,32 @@ static int qio_channel_websock_handshake_read(QIOChannelWebsock *ioc,
return 1; return 1;
} }
typedef struct QIOChannelWebsockData {
QIOTask *task;
} QIOChannelWebsockData;
static void qio_channel_websock_data_free(gpointer user_data)
{
QIOChannelWebsockData *data = user_data;
/*
* Usually 'task' will be NULL since the GSource
* callback will either complete the task or pass
* it on to a new GSource. We'll see a non-NULL
* task here only if the GSource was released before
* its callback triggers
*/
if (data->task) {
qio_task_free(data->task);
}
g_free(data);
}
static gboolean qio_channel_websock_handshake_send(QIOChannel *ioc, static gboolean qio_channel_websock_handshake_send(QIOChannel *ioc,
GIOCondition condition, GIOCondition condition,
gpointer user_data) gpointer user_data)
{ {
QIOTask *task = user_data; QIOChannelWebsockData *data = user_data;
QIOTask *task = data->task;
QIOChannelWebsock *wioc = QIO_CHANNEL_WEBSOCK( QIOChannelWebsock *wioc = QIO_CHANNEL_WEBSOCK(
qio_task_get_source(task)); qio_task_get_source(task));
Error *err = NULL; Error *err = NULL;
@ -545,7 +566,6 @@ static gboolean qio_channel_websock_handshake_send(QIOChannel *ioc,
trace_qio_channel_websock_handshake_fail(ioc, error_get_pretty(err)); trace_qio_channel_websock_handshake_fail(ioc, error_get_pretty(err));
qio_task_set_error(task, err); qio_task_set_error(task, err);
qio_task_complete(task); qio_task_complete(task);
qio_task_free(task);
wioc->hs_io_tag = 0; wioc->hs_io_tag = 0;
return FALSE; return FALSE;
} }
@ -562,7 +582,6 @@ static gboolean qio_channel_websock_handshake_send(QIOChannel *ioc,
trace_qio_channel_websock_handshake_complete(ioc); trace_qio_channel_websock_handshake_complete(ioc);
qio_task_complete(task); qio_task_complete(task);
} }
qio_task_free(task);
wioc->hs_io_tag = 0; wioc->hs_io_tag = 0;
return FALSE; return FALSE;
} }
@ -574,7 +593,8 @@ static gboolean qio_channel_websock_handshake_io(QIOChannel *ioc,
GIOCondition condition, GIOCondition condition,
gpointer user_data) gpointer user_data)
{ {
QIOTask *task = user_data; QIOChannelWebsockData *data = user_data, *newdata = NULL;
QIOTask *task = data->task;
QIOChannelWebsock *wioc = QIO_CHANNEL_WEBSOCK( QIOChannelWebsock *wioc = QIO_CHANNEL_WEBSOCK(
qio_task_get_source(task)); qio_task_get_source(task));
Error *err = NULL; Error *err = NULL;
@ -590,7 +610,6 @@ static gboolean qio_channel_websock_handshake_io(QIOChannel *ioc,
trace_qio_channel_websock_handshake_fail(ioc, error_get_pretty(err)); trace_qio_channel_websock_handshake_fail(ioc, error_get_pretty(err));
qio_task_set_error(task, err); qio_task_set_error(task, err);
qio_task_complete(task); qio_task_complete(task);
qio_task_free(task);
wioc->hs_io_tag = 0; wioc->hs_io_tag = 0;
return FALSE; return FALSE;
} }
@ -603,12 +622,14 @@ static gboolean qio_channel_websock_handshake_io(QIOChannel *ioc,
error_propagate(&wioc->io_err, err); error_propagate(&wioc->io_err, err);
trace_qio_channel_websock_handshake_reply(ioc); trace_qio_channel_websock_handshake_reply(ioc);
newdata = g_new0(QIOChannelWebsockData, 1);
newdata->task = g_steal_pointer(&data->task);
wioc->hs_io_tag = qio_channel_add_watch( wioc->hs_io_tag = qio_channel_add_watch(
wioc->master, wioc->master,
G_IO_OUT, G_IO_OUT,
qio_channel_websock_handshake_send, qio_channel_websock_handshake_send,
task, newdata,
NULL); qio_channel_websock_data_free);
return FALSE; return FALSE;
} }
@ -904,12 +925,12 @@ void qio_channel_websock_handshake(QIOChannelWebsock *ioc,
gpointer opaque, gpointer opaque,
GDestroyNotify destroy) GDestroyNotify destroy)
{ {
QIOTask *task; QIOChannelWebsockData *data = g_new0(QIOChannelWebsockData, 1);
task = qio_task_new(OBJECT(ioc), data->task = qio_task_new(OBJECT(ioc),
func, func,
opaque, opaque,
destroy); destroy);
trace_qio_channel_websock_handshake_start(ioc); trace_qio_channel_websock_handshake_start(ioc);
trace_qio_channel_websock_handshake_pending(ioc, G_IO_IN); trace_qio_channel_websock_handshake_pending(ioc, G_IO_IN);
@ -917,8 +938,8 @@ void qio_channel_websock_handshake(QIOChannelWebsock *ioc,
ioc->master, ioc->master,
G_IO_IN, G_IO_IN,
qio_channel_websock_handshake_io, qio_channel_websock_handshake_io,
task, data,
NULL); qio_channel_websock_data_free);
} }

Loading…
Cancel
Save