[PATCH wayland 6/9] connection: Make wl_closure_destroy() close fds of undispatched closures

Derek Foreman derekf at osg.samsung.com
Fri Apr 7 20:27:52 UTC 2017


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 <derekf at 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



More information about the wayland-devel mailing list