When we have a closure that can't be dispatched for some reason, and it
contains file descriptors, we must close those descriptors to prevent
leaking them.

Signed-off-by: Derek Foreman <der...@osg.samsung.com>
---
 src/connection.c         | 35 ++++++++++++++++++++++++++++++++---
 src/wayland-client.c     | 12 ++++++------
 src/wayland-private.h    |  2 +-
 src/wayland-server.c     |  6 +++---
 tests/connection-test.c  | 12 ++++++------
 tests/os-wrappers-test.c |  4 ++--
 6 files changed, 50 insertions(+), 21 deletions(-)

diff --git a/src/connection.c b/src/connection.c
index 934fddf..f2ebe06 100644
--- a/src/connection.c
+++ b/src/connection.c
@@ -548,6 +548,7 @@ wl_closure_marshal(struct wl_object *sender, uint32_t 
opcode,
                errno = ENOMEM;
                return NULL;
        }
+       closure->message = NULL;
 
        memcpy(closure->args, args, count * sizeof *args);
 
@@ -603,7 +604,7 @@ wl_closure_marshal(struct wl_object *sender, uint32_t 
opcode,
 err_null:
        for (i = 0; i < fd_count; i++)
                close(fds[i]);
-       wl_closure_destroy(closure);
+       wl_closure_destroy(closure, false);
        wl_log("error marshalling arguments for %s (signature %s): "
               "null value passed for arg %i\n", message->name,
               message->signature, i);
@@ -655,6 +656,7 @@ wl_connection_demarshal(struct wl_connection *connection,
                wl_connection_consume(connection, size);
                return NULL;
        }
+       closure->message = NULL;
 
        array_extra = closure->extra;
        p = (uint32_t *)(closure->extra + num_arrays);
@@ -801,7 +803,7 @@ wl_connection_demarshal(struct wl_connection *connection,
  err:
        for (i = 0; i < fd_count; i++)
                close(fds[i]);
-       wl_closure_destroy(closure);
+       wl_closure_destroy(closure, false);
        wl_connection_consume(connection, size);
 
        return NULL;
@@ -1244,8 +1246,35 @@ wl_closure_print(struct wl_closure *closure, struct 
wl_object *target, int send)
        fprintf(stderr, ")\n");
 }
 
+static int
+wl_closure_close_fds(struct wl_closure *closure)
+{
+       const struct wl_message *message = closure->message;
+       uint32_t i, count;
+       struct argument_details arg;
+       const char *signature = message->signature;
+
+       count = arg_count_for_signature(signature);
+       for (i = 0; i < count; i++) {
+               signature = get_next_argument(signature, &arg);
+               if (arg.type == 'h')
+                       close(closure->args[i].h);
+       }
+
+       return 0;
+}
+
 void
-wl_closure_destroy(struct wl_closure *closure)
+wl_closure_destroy(struct wl_closure *closure, bool dispatched)
 {
+       /* wl_closure_destroy has free() semantics */
+       if (!closure)
+               return;
+       /* If message is NULL then this closure failed during
+        * creation, and any fd cleanup has been done by the
+        * caller
+        */
+       if (!dispatched && closure->message)
+               wl_closure_close_fds(closure);
        free(closure);
 }
diff --git a/src/wayland-client.c b/src/wayland-client.c
index 3d7361e..a77cf71 100644
--- a/src/wayland-client.c
+++ b/src/wayland-client.c
@@ -274,7 +274,7 @@ wl_event_queue_release(struct wl_event_queue *queue)
                if (proxy_destroyed && !proxy->refcount)
                        free(proxy);
 
-               wl_closure_destroy(closure);
+               wl_closure_destroy(closure, false);
        }
 }
 
@@ -658,7 +658,7 @@ wl_proxy_marshal_array_constructor_versioned(struct 
wl_proxy *proxy,
        if (wl_closure_send(closure, proxy->display->connection))
                wl_abort("Error sending request: %s\n", strerror(errno));
 
-       wl_closure_destroy(closure);
+       wl_closure_destroy(closure, true);
 
  err_unlock:
        pthread_mutex_unlock(&proxy->display->mutex);
@@ -1243,12 +1243,12 @@ queue_event(struct wl_display *display, int len)
                return -1;
 
        if (create_proxies(proxy, closure) < 0) {
-               wl_closure_destroy(closure);
+               wl_closure_destroy(closure, false);
                return -1;
        }
 
        if (wl_closure_lookup_objects(closure, &display->objects) != 0) {
-               wl_closure_destroy(closure);
+               wl_closure_destroy(closure, false);
                return -1;
        }
 
@@ -1291,7 +1291,7 @@ dispatch_event(struct wl_display *display, struct 
wl_event_queue *queue)
                if (!proxy->refcount)
                        free(proxy);
 
-               wl_closure_destroy(closure);
+               wl_closure_destroy(closure, false);
                return;
        }
 
@@ -1311,7 +1311,7 @@ dispatch_event(struct wl_display *display, struct 
wl_event_queue *queue)
                                  &proxy->object, opcode, proxy->user_data);
        }
 
-       wl_closure_destroy(closure);
+       wl_closure_destroy(closure, true);
 
        pthread_mutex_lock(&display->mutex);
 }
diff --git a/src/wayland-private.h b/src/wayland-private.h
index 434cb04..d906a6f 100644
--- a/src/wayland-private.h
+++ b/src/wayland-private.h
@@ -216,7 +216,7 @@ wl_closure_print(struct wl_closure *closure,
                 struct wl_object *target, int send);
 
 void
-wl_closure_destroy(struct wl_closure *closure);
+wl_closure_destroy(struct wl_closure *closure, bool dispatched);
 
 extern wl_log_func_t wl_log_handler;
 
diff --git a/src/wayland-server.c b/src/wayland-server.c
index 82a3b01..b24fb65 100644
--- a/src/wayland-server.c
+++ b/src/wayland-server.c
@@ -225,7 +225,7 @@ handle_array(struct wl_resource *resource, uint32_t opcode,
 
        log_closure(resource, closure, true);
 
-       wl_closure_destroy(closure);
+       wl_closure_destroy(closure, true);
 }
 
 WL_EXPORT void
@@ -395,7 +395,7 @@ wl_client_connection_data(int fd, uint32_t mask, void *data)
                                               object->interface->name,
                                               object->id,
                                               message->name);
-                       wl_closure_destroy(closure);
+                       wl_closure_destroy(closure, false);
                        break;
                }
 
@@ -410,7 +410,7 @@ wl_client_connection_data(int fd, uint32_t mask, void *data)
                                            object, opcode);
                }
 
-               wl_closure_destroy(closure);
+               wl_closure_destroy(closure, true);
 
                if (client->error)
                        break;
diff --git a/tests/connection-test.c b/tests/connection-test.c
index 157e1bc..8e8fffe 100644
--- a/tests/connection-test.c
+++ b/tests/connection-test.c
@@ -211,7 +211,7 @@ marshal(struct marshal_data *data, const char *format, int 
size, ...)
 
        assert(closure);
        assert(wl_closure_send(closure, data->write_connection) == 0);
-       wl_closure_destroy(closure);
+       wl_closure_destroy(closure, true);
        assert(wl_connection_flush(data->write_connection) == size);
        assert(read(data->s[0], data->buffer, sizeof data->buffer) == size);
 
@@ -298,7 +298,7 @@ expected_fail_marshal_send(struct marshal_data *data, int 
expected_error,
        assert(wl_closure_send(closure, data->write_connection) < 0);
        assert(errno == expected_error);
 
-       wl_closure_destroy(closure);
+       wl_closure_destroy(closure, false);
 }
 
 TEST(connection_marshal_nullables)
@@ -405,7 +405,7 @@ demarshal(struct marshal_data *data, const char *format,
                                          size, &objects, &message);
        assert(closure);
        wl_closure_invoke(closure, WL_CLOSURE_INVOKE_SERVER, &object, 0, data);
-       wl_closure_destroy(closure);
+       wl_closure_destroy(closure, true);
 }
 
 TEST(connection_demarshal)
@@ -475,7 +475,7 @@ marshal_demarshal(struct marshal_data *data,
 
        assert(closure);
        assert(wl_closure_send(closure, data->write_connection) == 0);
-       wl_closure_destroy(closure);
+       wl_closure_destroy(closure, true);
        assert(wl_connection_flush(data->write_connection) == size);
 
        assert(wl_connection_read(data->read_connection) == size);
@@ -486,7 +486,7 @@ marshal_demarshal(struct marshal_data *data,
                                          size, &objects, &message);
        assert(closure);
        wl_closure_invoke(closure, WL_CLOSURE_INVOKE_SERVER, &object, 0, data);
-       wl_closure_destroy(closure);
+       wl_closure_destroy(closure, true);
 }
 
 TEST(connection_marshal_demarshal)
@@ -592,7 +592,7 @@ marshal_helper(const char *format, void *handler, ...)
        assert(closure);
        done = 0;
        wl_closure_invoke(closure, WL_CLOSURE_INVOKE_SERVER, &object, 0, &done);
-       wl_closure_destroy(closure);
+       wl_closure_destroy(closure, true);
        assert(done);
 }
 
diff --git a/tests/os-wrappers-test.c b/tests/os-wrappers-test.c
index 102622c..ddcd2f4 100644
--- a/tests/os-wrappers-test.c
+++ b/tests/os-wrappers-test.c
@@ -247,7 +247,7 @@ marshal_demarshal(struct marshal_data *data,
 
        assert(closure);
        assert(wl_closure_send(closure, data->write_connection) == 0);
-       wl_closure_destroy(closure);
+       wl_closure_destroy(closure, true);
        assert(wl_connection_flush(data->write_connection) == size);
 
        assert(wl_connection_read(data->read_connection) == size);
@@ -258,7 +258,7 @@ marshal_demarshal(struct marshal_data *data,
                                          size, &objects, &message);
        assert(closure);
        wl_closure_invoke(closure, WL_CLOSURE_INVOKE_SERVER, &object, 0, data);
-       wl_closure_destroy(closure);
+       wl_closure_destroy(closure, true);
 }
 
 static void
-- 
2.11.0

_______________________________________________
wayland-devel mailing list
wayland-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/wayland-devel

Reply via email to