Wayland Embedder: Fix FD leak with inert objects
Freshly deleted objects are temporarily "inert" until their destruction is acknowledged by the compositor. Inert objects are ignored. By doing so, we mistakenly returned too early and missed some FD cleanup logic. This patch ensures that any outstanding FDs are always closed by moving its logic outside of the message handling routine. (cherry picked from commit 6e5d1e00e02cf9086224b5eb3258f901a26de413)
This commit is contained in:
committed by
Thaddeus Crews
parent
d376ca77dc
commit
6a0b2db3ac
@@ -2351,13 +2351,10 @@ void WaylandEmbedder::shutdown() {
|
||||
}
|
||||
}
|
||||
|
||||
Error WaylandEmbedder::handle_msg_info(Client *client, const struct msg_info *info, uint32_t *buf, int *fds_requested) {
|
||||
Error WaylandEmbedder::handle_msg_info(Client *client, const struct msg_info *info, uint32_t *buf, LocalVector<int> &r_sent_fds) {
|
||||
ERR_FAIL_NULL_V(info, ERR_BUG);
|
||||
ERR_FAIL_NULL_V(fds_requested, ERR_BUG);
|
||||
ERR_FAIL_NULL_V_MSG(info->direction == ProxyDirection::COMPOSITOR && client, ERR_BUG, "Wait, where did this message come from?");
|
||||
|
||||
*fds_requested = 0;
|
||||
|
||||
WaylandObject *object = nullptr;
|
||||
|
||||
uint32_t global_id = INVALID_ID;
|
||||
@@ -2410,17 +2407,15 @@ Error WaylandEmbedder::handle_msg_info(Client *client, const struct msg_info *in
|
||||
}
|
||||
ERR_FAIL_NULL_V(message, ERR_BUG);
|
||||
|
||||
*fds_requested = String(message->signature).count("h");
|
||||
LocalVector<int> sent_fds;
|
||||
|
||||
if (*fds_requested > 0) {
|
||||
DEBUG_LOG_WAYLAND_EMBED(vformat("Requested %d FDs.", *fds_requested));
|
||||
int fds_requested = String(message->signature).count("h");
|
||||
if (fds_requested > 0) {
|
||||
DEBUG_LOG_WAYLAND_EMBED(vformat("Requested %d FDs.", fds_requested));
|
||||
|
||||
List<int> &fd_queue = info->direction == ProxyDirection::COMPOSITOR ? client->fds : compositor_fds;
|
||||
for (int i = 0; i < *fds_requested; ++i) {
|
||||
for (int i = 0; i < fds_requested; ++i) {
|
||||
ERR_FAIL_COND_V_MSG(fd_queue.is_empty(), ERR_BUG, "Out of FDs.");
|
||||
DEBUG_LOG_WAYLAND_EMBED(vformat("Fetching FD %d.", fd_queue.front()->get()));
|
||||
sent_fds.push_back(fd_queue.front()->get());
|
||||
r_sent_fds.push_back(fd_queue.front()->get());
|
||||
fd_queue.pop_front();
|
||||
}
|
||||
|
||||
@@ -2429,6 +2424,7 @@ Error WaylandEmbedder::handle_msg_info(Client *client, const struct msg_info *in
|
||||
|
||||
if (object->destroyed) {
|
||||
DEBUG_LOG_WAYLAND_EMBED("Ignoring message for inert object.");
|
||||
|
||||
// Inert object.
|
||||
return OK;
|
||||
}
|
||||
@@ -2451,7 +2447,7 @@ Error WaylandEmbedder::handle_msg_info(Client *client, const struct msg_info *in
|
||||
DEBUG_LOG_WAYLAND_EMBED("Falling back to generic handler.");
|
||||
|
||||
if (handle_generic_msg(client, object, message, info, buf)) {
|
||||
send_raw_message(compositor_socket, { { buf, info->size } }, sent_fds);
|
||||
send_raw_message(compositor_socket, { { buf, info->size } }, r_sent_fds);
|
||||
}
|
||||
} else {
|
||||
uint32_t global_name = 0;
|
||||
@@ -2522,7 +2518,7 @@ Error WaylandEmbedder::handle_msg_info(Client *client, const struct msg_info *in
|
||||
buf[0] = instance_id;
|
||||
|
||||
if (handle_generic_msg(&c, local_obj.get(), message, info, buf, instance_id)) {
|
||||
send_raw_message(c.socket, { { buf, info->size } }, sent_fds);
|
||||
send_raw_message(c.socket, { { buf, info->size } }, r_sent_fds);
|
||||
}
|
||||
|
||||
handled = true;
|
||||
@@ -2558,7 +2554,7 @@ Error WaylandEmbedder::handle_msg_info(Client *client, const struct msg_info *in
|
||||
DEBUG_LOG_WAYLAND_EMBED("Falling back to generic handler.");
|
||||
|
||||
if (handle_generic_msg(&c, local_obj.get(), message, info, buf)) {
|
||||
send_raw_message(c.socket, { { buf, info->size } }, sent_fds);
|
||||
send_raw_message(c.socket, { { buf, info->size } }, r_sent_fds);
|
||||
}
|
||||
|
||||
handled = true;
|
||||
@@ -2594,7 +2590,7 @@ Error WaylandEmbedder::handle_msg_info(Client *client, const struct msg_info *in
|
||||
buf[0] = local_id;
|
||||
|
||||
if (handle_generic_msg(client, local_obj.get(), message, info, buf)) {
|
||||
send_raw_message(client->socket, { { buf, info->size } }, sent_fds);
|
||||
send_raw_message(client->socket, { { buf, info->size } }, r_sent_fds);
|
||||
}
|
||||
} else {
|
||||
WARN_PRINT_ONCE(vformat("[Wayland Embedder] Unexpected client-less event from %s#g0x%x. Object has probably leaked.", object->interface->name, global_id));
|
||||
@@ -2603,11 +2599,6 @@ Error WaylandEmbedder::handle_msg_info(Client *client, const struct msg_info *in
|
||||
}
|
||||
}
|
||||
|
||||
for (int fd : sent_fds) {
|
||||
DEBUG_LOG_WAYLAND_EMBED(vformat("Closing fd %d.", fd));
|
||||
close(fd);
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
@@ -2730,8 +2721,6 @@ Error WaylandEmbedder::handle_sock(int p_fd) {
|
||||
full_msg.msg_control = nullptr;
|
||||
full_msg.msg_controllen = 0;
|
||||
|
||||
int fds_requested = 0;
|
||||
|
||||
Client *client = nullptr;
|
||||
if (p_fd == compositor_socket) {
|
||||
// Let's figure out the recipient of the message.
|
||||
@@ -2747,12 +2736,20 @@ Error WaylandEmbedder::handle_sock(int p_fd) {
|
||||
client = &clients[p_fd];
|
||||
}
|
||||
|
||||
if (handle_msg_info(client, &info, msg_buf.ptr(), &fds_requested) != OK) {
|
||||
return ERR_BUG;
|
||||
LocalVector<int> sent_fds;
|
||||
Error err = handle_msg_info(client, &info, msg_buf.ptr(), sent_fds);
|
||||
|
||||
for (int fd : sent_fds) {
|
||||
DEBUG_LOG_WAYLAND_EMBED(vformat("Closing fd %d.", fd));
|
||||
close(fd);
|
||||
}
|
||||
|
||||
DEBUG_LOG_WAYLAND_EMBED(" === END PACKET === ");
|
||||
|
||||
if (err != OK) {
|
||||
return ERR_BUG;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -610,7 +610,7 @@ class WaylandEmbedder {
|
||||
void shutdown();
|
||||
|
||||
bool handle_generic_msg(Client *client, const WaylandObject *p_object, const struct wl_message *message, const struct msg_info *info, uint32_t *buf, uint32_t instance_id = INVALID_ID);
|
||||
Error handle_msg_info(Client *client, const struct msg_info *info, uint32_t *buf, int *fds_requested);
|
||||
Error handle_msg_info(Client *client, const struct msg_info *info, uint32_t *buf, LocalVector<int> &r_fds_requested);
|
||||
Error handle_sock(int p_fd);
|
||||
void handle_fd(int p_fd, int p_revents);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user