Merge branch 'proxy-creation-with-no-queue' into 'main'

client: fix crash when creating proxies with no queue

See merge request wayland/wayland!494
This commit is contained in:
Loïc Yhuel 2025-09-19 09:09:45 +00:00
commit cfbcc454a3
2 changed files with 67 additions and 3 deletions

View file

@ -499,7 +499,10 @@ proxy_create(struct wl_proxy *factory, const struct wl_interface *interface,
return NULL;
}
wl_list_insert(&proxy->queue->proxy_list, &proxy->queue_link);
if (proxy->queue != NULL)
wl_list_insert(&proxy->queue->proxy_list, &proxy->queue_link);
else
wl_list_init(&proxy->queue_link);
return proxy;
}
@ -560,7 +563,10 @@ wl_proxy_create_for_id(struct wl_proxy *factory,
return NULL;
}
wl_list_insert(&proxy->queue->proxy_list, &proxy->queue_link);
if (proxy->queue != NULL)
wl_list_insert(&proxy->queue->proxy_list, &proxy->queue_link);
else
wl_list_init(&proxy->queue_link);
return proxy;
}
@ -2801,7 +2807,10 @@ wl_proxy_create_wrapper(void *proxy)
wrapper->flags = WL_PROXY_FLAG_WRAPPER;
wrapper->refcount = 1;
wl_list_insert(&wrapper->queue->proxy_list, &wrapper->queue_link);
if (wrapper->queue != NULL)
wl_list_insert(&wrapper->queue->proxy_list, &wrapper->queue_link);
else
wl_list_init(&wrapper->queue_link);
pthread_mutex_unlock(&wrapped_proxy->display->mutex);

View file

@ -634,6 +634,49 @@ client_test_queue_dispatch_timeout(void)
exit(0);
}
/* Try to use a proxy with a destroyed queue as a factory for
* another proxy (either normal or wrapper). This should succeed
* although the new proxy may not be useful until a queue is attached.
* The following code is safe to perform in the context of the test, since
* we are not flushing the display write buffer, neither explicitly
* (wl_display_flush()) nor implicitly (we don't place enough data to
* fill the display buffer and cause an auto-flush). */
static void
client_test_queue_destroy_then_use_proxy_as_factory(void)
{
struct wl_display *display;
struct wl_event_queue *queue;
struct wl_registry *registry, *registry_wrapper;
struct wl_proxy *proxy;
display = wl_display_connect(NULL);
assert(display);
/* Create registry with a queue that's immediately destroyed. */
queue = wl_display_create_queue(display);
assert(queue);
registry = wl_display_get_registry(display);
assert(registry);
wl_proxy_set_queue((struct wl_proxy *) registry, queue);
wl_event_queue_destroy(queue);
/* Scenario 1: Create a proxy using the registry (never flushed,
* so details don't matter). */
proxy = wl_registry_bind(registry, 1000, &wl_output_interface, 1);
assert(proxy);
/* Scenario 2: Create a wrapper proxy using the registry. */
registry_wrapper = wl_proxy_create_wrapper(registry);
assert(registry_wrapper);
wl_proxy_wrapper_destroy((struct wl_proxy *) registry_wrapper);
wl_proxy_destroy(proxy);
wl_registry_destroy(registry);
wl_display_disconnect(display);
exit(0);
}
static void
dummy_bind(struct wl_client *client,
void *data, uint32_t version, uint32_t id)
@ -796,3 +839,15 @@ TEST(queue_dispatch_timeout)
display_destroy(d);
}
TEST(queue_destroy_then_use_proxy_as_factory)
{
struct display *d = display_create();
test_set_timeout(2);
client_create_noarg(d, client_test_queue_destroy_then_use_proxy_as_factory);
display_run(d);
display_destroy(d);
}