client: Do not warn about attached proxies on default queue destruction.
authorAlexandros Frantzis <alexandros.frantzis@collabora.com>
Tue, 28 Feb 2023 21:42:59 +0000 (23:42 +0200)
committerAlexandros Frantzis <alexandros.frantzis@collabora.com>
Wed, 1 Mar 2023 13:50:02 +0000 (15:50 +0200)
If the default queue is being destroyed, the client is disconnecting
from the wl_display, so there is no possibility of subsequent events
being queued to the destroyed default queue, which is what this warning
is about.

Note that interacting with (e.g., destroying) a wl_proxy after its
wl_display is destroyed is a certain memory error, and this warning will
indirectly warn about this issue. However, this memory error should be
detected and warned about through a more deliberate mechanism.

Signed-off-by: Alexandros Frantzis <alexandros.frantzis@collabora.com>
src/wayland-client.c
tests/queue-test.c

index a50fc18..054c0c7 100644 (file)
@@ -304,14 +304,18 @@ wl_event_queue_release(struct wl_event_queue *queue)
        if (!wl_list_empty(&queue->proxy_list)) {
                struct wl_proxy *proxy, *tmp;
 
-               wl_log("warning: queue %p destroyed while proxies still "
-                      "attached:\n", queue);
+               if (queue != &queue->display->default_queue) {
+                       wl_log("warning: queue %p destroyed while proxies "
+                              "still attached:\n", queue);
+               }
 
                wl_list_for_each_safe(proxy, tmp, &queue->proxy_list,
                                      queue_link) {
-                       wl_log("  %s@%u still attached\n",
-                              proxy->object.interface->name,
-                              proxy->object.id);
+                       if (queue != &queue->display->default_queue) {
+                               wl_log("  %s@%u still attached\n",
+                                      proxy->object.interface->name,
+                                      proxy->object.id);
+                       }
                        proxy->queue = NULL;
                        wl_list_remove(&proxy->queue_link);
                        wl_list_init(&proxy->queue_link);
index 63abc19..4129310 100644 (file)
@@ -308,12 +308,22 @@ client_test_queue_set_queue_race(void)
 }
 
 static char *
-map_file(int fd, size_t *len)
+maybe_map_file(int fd, size_t *len)
 {
        char *data;
 
        *len = lseek(fd, 0, SEEK_END);
        data = mmap(0, *len, PROT_READ, MAP_PRIVATE, fd, 0);
+
+       return data;
+}
+
+static char *
+map_file(int fd, size_t *len)
+{
+       char *data;
+
+       data = maybe_map_file(fd, len);
        assert(data != MAP_FAILED && "Failed to mmap file");
 
        return data;
@@ -423,6 +433,45 @@ client_test_queue_proxy_event_to_destroyed_queue(void)
 }
 
 static void
+client_test_queue_destroy_default_with_attached_proxies(void)
+{
+       struct wl_display *display;
+       struct wl_callback *callback;
+       char *log;
+       size_t log_len;
+       char callback_name[24];
+       int ret;
+
+       display = wl_display_connect(NULL);
+       assert(display);
+
+       /* Create a sync dispatching events on the default queue. */
+       callback = wl_display_sync(display);
+       assert(callback != NULL);
+
+       /* Destroy the default queue (by disconnecting) before the attached
+        * object. */
+       wl_display_disconnect(display);
+
+       /* Check that the log does not contain any warning about the attached
+        * wl_callback proxy. */
+       log = maybe_map_file(client_log_fd, &log_len);
+       ret = snprintf(callback_name, sizeof(callback_name), "wl_callback@%u",
+                      wl_proxy_get_id((struct wl_proxy *) callback));
+       assert(ret > 0 && ret < (int)sizeof(callback_name) &&
+              "callback name creation failed (possibly truncated)");
+       assert(log == MAP_FAILED || strstr(log, callback_name) == NULL);
+       if (log != MAP_FAILED)
+               munmap(log, log_len);
+
+       /* HACK: Directly free the memory of the wl_callback proxy to appease
+        * ASan. We would normally use wl_callback_destroy(), but since we have
+        * destroyed the associated wl_display, using this function would lead
+        * to memory errors. */
+       free(callback);
+}
+
+static void
 dummy_bind(struct wl_client *client,
           void *data, uint32_t version, uint32_t id)
 {
@@ -536,3 +585,15 @@ TEST(queue_proxy_event_to_destroyed_queue)
        /* Check that the client aborted. */
        display_destroy_expect_signal(d, SIGABRT);
 }
+
+TEST(queue_destroy_default_with_attached_proxies)
+{
+       struct display *d = display_create();
+
+       test_set_timeout(2);
+
+       client_create_noarg(d, client_test_queue_destroy_default_with_attached_proxies);
+       display_run(d);
+
+       display_destroy(d);
+}