mirror of
https://gitlab.freedesktop.org/wayland/wayland.git
synced 2026-03-27 07:58:47 -04:00
client: Abort when trying to add an event to a destroyed queue
Detect when we are trying to add an event to a destroyed queue, and abort instead of causing a use-after-free memory error. This situation can occur when an wl_event_queue is destroyed before its attached wl_proxy objects. Signed-off-by: Alexandros Frantzis <alexandros.frantzis@collabora.com>
This commit is contained in:
parent
e09010f470
commit
d72f9007c3
2 changed files with 66 additions and 0 deletions
|
|
@ -312,6 +312,7 @@ wl_event_queue_release(struct wl_event_queue *queue)
|
||||||
wl_log(" %s@%u still attached\n",
|
wl_log(" %s@%u still attached\n",
|
||||||
proxy->object.interface->name,
|
proxy->object.interface->name,
|
||||||
proxy->object.id);
|
proxy->object.id);
|
||||||
|
proxy->queue = NULL;
|
||||||
wl_list_remove(&proxy->queue_link);
|
wl_list_remove(&proxy->queue_link);
|
||||||
wl_list_init(&proxy->queue_link);
|
wl_list_init(&proxy->queue_link);
|
||||||
}
|
}
|
||||||
|
|
@ -541,6 +542,7 @@ proxy_destroy(struct wl_proxy *proxy)
|
||||||
|
|
||||||
proxy->flags |= WL_PROXY_FLAG_DESTROYED;
|
proxy->flags |= WL_PROXY_FLAG_DESTROYED;
|
||||||
|
|
||||||
|
proxy->queue = NULL;
|
||||||
wl_list_remove(&proxy->queue_link);
|
wl_list_remove(&proxy->queue_link);
|
||||||
wl_list_init(&proxy->queue_link);
|
wl_list_init(&proxy->queue_link);
|
||||||
|
|
||||||
|
|
@ -1564,6 +1566,9 @@ queue_event(struct wl_display *display, int len)
|
||||||
else
|
else
|
||||||
queue = proxy->queue;
|
queue = proxy->queue;
|
||||||
|
|
||||||
|
if (!queue)
|
||||||
|
wl_abort("Tried to add event to destroyed queue\n");
|
||||||
|
|
||||||
wl_list_insert(queue->event_list.prev, &closure->link);
|
wl_list_insert(queue->event_list.prev, &closure->link);
|
||||||
|
|
||||||
return size;
|
return size;
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,7 @@
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include <signal.h>
|
||||||
|
|
||||||
#include "wayland-client.h"
|
#include "wayland-client.h"
|
||||||
#include "wayland-server.h"
|
#include "wayland-server.h"
|
||||||
|
|
@ -384,6 +385,43 @@ client_test_queue_destroy_with_attached_proxies(void)
|
||||||
wl_display_disconnect(display);
|
wl_display_disconnect(display);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
client_test_queue_proxy_event_to_destroyed_queue(void)
|
||||||
|
{
|
||||||
|
struct wl_event_queue *queue;
|
||||||
|
struct wl_display *display;
|
||||||
|
struct wl_display *display_wrapper;
|
||||||
|
struct wl_callback *callback;
|
||||||
|
|
||||||
|
display = wl_display_connect(NULL);
|
||||||
|
assert(display);
|
||||||
|
|
||||||
|
/* Pretend we are in a separate thread where a thread-local queue is
|
||||||
|
* used. */
|
||||||
|
queue = wl_display_create_queue(display);
|
||||||
|
assert(queue);
|
||||||
|
|
||||||
|
/* Create a sync dispatching events on the thread-local queue. */
|
||||||
|
display_wrapper = wl_proxy_create_wrapper(display);
|
||||||
|
assert(display_wrapper);
|
||||||
|
wl_proxy_set_queue((struct wl_proxy *) display_wrapper, queue);
|
||||||
|
callback = wl_display_sync(display_wrapper);
|
||||||
|
wl_proxy_wrapper_destroy(display_wrapper);
|
||||||
|
assert(callback != NULL);
|
||||||
|
wl_display_flush(display);
|
||||||
|
|
||||||
|
/* Destroy the queue before the attached object. */
|
||||||
|
wl_event_queue_destroy(queue);
|
||||||
|
|
||||||
|
/* During this roundtrip we should receive the done event on 'callback',
|
||||||
|
* try to queue it to the destroyed queue, and abort. */
|
||||||
|
wl_display_roundtrip(display);
|
||||||
|
|
||||||
|
wl_callback_destroy(callback);
|
||||||
|
|
||||||
|
wl_display_disconnect(display);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
dummy_bind(struct wl_client *client,
|
dummy_bind(struct wl_client *client,
|
||||||
void *data, uint32_t version, uint32_t id)
|
void *data, uint32_t version, uint32_t id)
|
||||||
|
|
@ -475,3 +513,26 @@ TEST(queue_destroy_with_attached_proxies)
|
||||||
|
|
||||||
display_destroy(d);
|
display_destroy(d);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(queue_proxy_event_to_destroyed_queue)
|
||||||
|
{
|
||||||
|
struct display *d = display_create();
|
||||||
|
struct client_info *ci;
|
||||||
|
char *client_log;
|
||||||
|
size_t client_log_len;
|
||||||
|
|
||||||
|
test_set_timeout(2);
|
||||||
|
|
||||||
|
ci = client_create_noarg(d, client_test_queue_proxy_event_to_destroyed_queue);
|
||||||
|
display_run(d);
|
||||||
|
|
||||||
|
/* Check that the final line in the log mentions the expected reason
|
||||||
|
* for the abort. */
|
||||||
|
client_log = map_file(ci->log_fd, &client_log_len);
|
||||||
|
assert(!strcmp(last_line_of(client_log),
|
||||||
|
"Tried to add event to destroyed queue\n"));
|
||||||
|
munmap(client_log, client_log_len);
|
||||||
|
|
||||||
|
/* Check that the client aborted. */
|
||||||
|
display_destroy_expect_signal(d, SIGABRT);
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue