freescale-layer: wayland: port patches from scarthgap-6.6.23-2.0.0 meta-imx

All wayland-related recipes save for these patches are already available in
meta-freescale

https://onedigi.atlassian.net/browse/DEL-9011
https://onedigi.atlassian.net/browse/DEL-9081

Signed-off-by: Gabriel Valcazar <gabriel.valcazar@digi.com>
This commit is contained in:
Gabriel Valcazar 2024-06-18 16:42:50 +02:00
parent d7ee944abb
commit 2d6ab24a6a
10 changed files with 1603 additions and 0 deletions

View File

@ -0,0 +1,134 @@
From 7a890bbf1d6eef0f1b52a701640afe2e495aaa8c Mon Sep 17 00:00:00 2001
From: Wujian Sun <wujian.sun_1@nxp.com>
Date: Wed, 29 Nov 2023 17:04:51 +0800
Subject: [PATCH 1/4] Revert "client: Do not warn about attached proxies on
default queue destruction."
This reverts commit b01a85dfd5e8cda7170b7ba6fe66fc3800f93990.
Upstream-Status: Inappropriate [i.MX specific]
---
src/wayland-client.c | 14 ++++------
tests/queue-test.c | 63 +-------------------------------------------
2 files changed, 6 insertions(+), 71 deletions(-)
diff --git a/src/wayland-client.c b/src/wayland-client.c
index 105f9be..baebfa9 100644
--- a/src/wayland-client.c
+++ b/src/wayland-client.c
@@ -304,18 +304,14 @@ wl_event_queue_release(struct wl_event_queue *queue)
if (!wl_list_empty(&queue->proxy_list)) {
struct wl_proxy *proxy, *tmp;
- if (queue != &queue->display->default_queue) {
- wl_log("warning: queue %p destroyed while proxies "
- "still attached:\n", 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) {
- if (queue != &queue->display->default_queue) {
- wl_log(" %s@%u still attached\n",
- proxy->object.interface->name,
- proxy->object.id);
- }
+ 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);
diff --git a/tests/queue-test.c b/tests/queue-test.c
index 4129310..63abc19 100644
--- a/tests/queue-test.c
+++ b/tests/queue-test.c
@@ -308,22 +308,12 @@ client_test_queue_set_queue_race(void)
}
static char *
-maybe_map_file(int fd, size_t *len)
+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;
@@ -432,45 +422,6 @@ client_test_queue_proxy_event_to_destroyed_queue(void)
wl_display_disconnect(display);
}
-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)
@@ -585,15 +536,3 @@ 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);
-}
--
2.17.1

View File

@ -0,0 +1,129 @@
From ebc08059a18a66f0296e530351be830e8f3e7e53 Mon Sep 17 00:00:00 2001
From: Wujian Sun <wujian.sun_1@nxp.com>
Date: Wed, 29 Nov 2023 17:05:39 +0800
Subject: [PATCH 2/4] Revert "client: Abort when trying to add an event to a
destroyed queue"
This reverts commit d72f9007c36f2f8ad2dc26178545e8a7f5b993a0.
Upstream-Status: Inappropriate [i.MX specific]
---
src/wayland-client.c | 5 ----
tests/queue-test.c | 61 --------------------------------------------
2 files changed, 66 deletions(-)
diff --git a/src/wayland-client.c b/src/wayland-client.c
index baebfa9..564e227 100644
--- a/src/wayland-client.c
+++ b/src/wayland-client.c
@@ -312,7 +312,6 @@ wl_event_queue_release(struct wl_event_queue *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);
}
@@ -542,7 +541,6 @@ proxy_destroy(struct wl_proxy *proxy)
proxy->flags |= WL_PROXY_FLAG_DESTROYED;
- proxy->queue = NULL;
wl_list_remove(&proxy->queue_link);
wl_list_init(&proxy->queue_link);
@@ -1567,9 +1565,6 @@ queue_event(struct wl_display *display, int len)
else
queue = proxy->queue;
- if (!queue)
- wl_abort("Tried to add event to destroyed queue\n");
-
wl_list_insert(queue->event_list.prev, &closure->link);
return size;
diff --git a/tests/queue-test.c b/tests/queue-test.c
index 63abc19..f9254f7 100644
--- a/tests/queue-test.c
+++ b/tests/queue-test.c
@@ -34,7 +34,6 @@
#include <sys/types.h>
#include <sys/wait.h>
#include <assert.h>
-#include <signal.h>
#include "wayland-client.h"
#include "wayland-server.h"
@@ -385,43 +384,6 @@ client_test_queue_destroy_with_attached_proxies(void)
wl_display_disconnect(display);
}
-static void
-client_test_queue_proxy_event_to_destroyed_queue(void)
-{
- struct wl_event_queue *queue;
- struct wl_display *display;
- struct wl_display *display_wrapper;
- struct wl_callback *callback;
-
- display = wl_display_connect(NULL);
- assert(display);
-
- /* Pretend we are in a separate thread where a thread-local queue is
- * used. */
- queue = wl_display_create_queue(display);
- assert(queue);
-
- /* Create a sync dispatching events on the thread-local queue. */
- display_wrapper = wl_proxy_create_wrapper(display);
- assert(display_wrapper);
- wl_proxy_set_queue((struct wl_proxy *) display_wrapper, queue);
- callback = wl_display_sync(display_wrapper);
- wl_proxy_wrapper_destroy(display_wrapper);
- assert(callback != NULL);
- wl_display_flush(display);
-
- /* Destroy the queue before the attached object. */
- wl_event_queue_destroy(queue);
-
- /* During this roundtrip we should receive the done event on 'callback',
- * try to queue it to the destroyed queue, and abort. */
- wl_display_roundtrip(display);
-
- wl_callback_destroy(callback);
-
- wl_display_disconnect(display);
-}
-
static void
dummy_bind(struct wl_client *client,
void *data, uint32_t version, uint32_t id)
@@ -513,26 +475,3 @@ TEST(queue_destroy_with_attached_proxies)
display_destroy(d);
}
-
-TEST(queue_proxy_event_to_destroyed_queue)
-{
- struct display *d = display_create();
- struct client_info *ci;
- char *client_log;
- size_t client_log_len;
-
- test_set_timeout(2);
-
- ci = client_create_noarg(d, client_test_queue_proxy_event_to_destroyed_queue);
- display_run(d);
-
- /* Check that the final line in the log mentions the expected reason
- * for the abort. */
- client_log = map_file(ci->log_fd, &client_log_len);
- assert(!strcmp(last_line_of(client_log),
- "Tried to add event to destroyed queue\n"));
- munmap(client_log, client_log_len);
-
- /* Check that the client aborted. */
- display_destroy_expect_signal(d, SIGABRT);
-}
--
2.17.1

View File

@ -0,0 +1,163 @@
From 629b02dfa53ed6dc19378853b6f2ca3a308e30fe Mon Sep 17 00:00:00 2001
From: Wujian Sun <wujian.sun_1@nxp.com>
Date: Wed, 29 Nov 2023 17:05:59 +0800
Subject: [PATCH 3/4] Revert "client: Warn when a queue is destroyed with
attached proxies"
This reverts commit 0ba650202e742b23150054cf0740168cd529b010.
Upstream-Status: Inappropriate [i.MX specific]
---
src/wayland-client.c | 16 --------
tests/queue-test.c | 93 --------------------------------------------
2 files changed, 109 deletions(-)
diff --git a/src/wayland-client.c b/src/wayland-client.c
index 564e227..8c897d4 100644
--- a/src/wayland-client.c
+++ b/src/wayland-client.c
@@ -301,22 +301,6 @@ wl_event_queue_release(struct wl_event_queue *queue)
{
struct wl_closure *closure;
- if (!wl_list_empty(&queue->proxy_list)) {
- struct wl_proxy *proxy, *tmp;
-
- 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);
- wl_list_remove(&proxy->queue_link);
- wl_list_init(&proxy->queue_link);
- }
- }
-
while (!wl_list_empty(&queue->event_list)) {
closure = wl_container_of(queue->event_list.next,
closure, link);
diff --git a/tests/queue-test.c b/tests/queue-test.c
index f9254f7..86a3602 100644
--- a/tests/queue-test.c
+++ b/tests/queue-test.c
@@ -23,14 +23,11 @@
* SOFTWARE.
*/
-#define _GNU_SOURCE /* For memrchr */
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <stdbool.h>
-#include <string.h>
#include <unistd.h>
-#include <sys/mman.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <assert.h>
@@ -306,84 +303,6 @@ client_test_queue_set_queue_race(void)
wl_display_disconnect(display);
}
-static char *
-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);
- assert(data != MAP_FAILED && "Failed to mmap file");
-
- return data;
-}
-
-static char *
-last_line_of(char *s)
-{
- size_t len = strlen(s);
- char *last;
-
- last = memrchr(s, '\n', len);
- /* If we found a newline at end of string, find the previous one. */
- if (last && last[1] == 0)
- last = memrchr(s, '\n', len - 1);
- /* If we have a newline, the last line starts after the newline.
- * Otherwise, the whole string is the last line. */
- if (last)
- last += 1;
- else
- last = s;
-
- return last;
-}
-
-static void
-client_test_queue_destroy_with_attached_proxies(void)
-{
- struct wl_event_queue *queue;
- struct wl_display *display;
- struct wl_display *display_wrapper;
- struct wl_callback *callback;
- char *log;
- size_t log_len;
- char callback_name[24];
- int ret;
-
- display = wl_display_connect(NULL);
- assert(display);
-
- /* Pretend we are in a separate thread where a thread-local queue is
- * used. */
- queue = wl_display_create_queue(display);
- assert(queue);
-
- /* Create a sync dispatching events on the thread-local queue. */
- display_wrapper = wl_proxy_create_wrapper(display);
- assert(display_wrapper);
- wl_proxy_set_queue((struct wl_proxy *) display_wrapper, queue);
- callback = wl_display_sync(display_wrapper);
- wl_proxy_wrapper_destroy(display_wrapper);
- assert(callback != NULL);
-
- /* Destroy the queue before the attached object. */
- wl_event_queue_destroy(queue);
-
- /* Check that the log contains some information about the attached
- * wl_callback proxy. */
- log = 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(strstr(last_line_of(log), callback_name));
- munmap(log, log_len);
-
- wl_callback_destroy(callback);
-
- wl_display_disconnect(display);
-}
-
static void
dummy_bind(struct wl_client *client,
void *data, uint32_t version, uint32_t id)
@@ -463,15 +382,3 @@ TEST(queue_set_queue_race)
display_destroy(d);
}
-
-TEST(queue_destroy_with_attached_proxies)
-{
- struct display *d = display_create();
-
- test_set_timeout(2);
-
- client_create_noarg(d, client_test_queue_destroy_with_attached_proxies);
- display_run(d);
-
- display_destroy(d);
-}
--
2.17.1

View File

@ -0,0 +1,107 @@
From 5780ff48cd5e40c2669f3cd94653ab7f850d7a98 Mon Sep 17 00:00:00 2001
From: Wujian Sun <wujian.sun_1@nxp.com>
Date: Wed, 29 Nov 2023 17:06:22 +0800
Subject: [PATCH 4/4] Revert "client: Track the proxies attached to a queue"
This reverts commit 674145dc3f621e5a3673714c7527d0e1c5336ab1.
Upstream-Status: Inappropriate [i.MX specific]
---
src/wayland-client.c | 22 ----------------------
1 file changed, 22 deletions(-)
diff --git a/src/wayland-client.c b/src/wayland-client.c
index 8c897d4..b57bfe9 100644
--- a/src/wayland-client.c
+++ b/src/wayland-client.c
@@ -70,12 +70,10 @@ struct wl_proxy {
wl_dispatcher_func_t dispatcher;
uint32_t version;
const char * const *tag;
- struct wl_list queue_link; /**< in struct wl_event_queue::proxy_list */
};
struct wl_event_queue {
struct wl_list event_list;
- struct wl_list proxy_list; /**< struct wl_proxy::queue_link */
struct wl_display *display;
};
@@ -223,7 +221,6 @@ static void
wl_event_queue_init(struct wl_event_queue *queue, struct wl_display *display)
{
wl_list_init(&queue->event_list);
- wl_list_init(&queue->proxy_list);
queue->display = display;
}
@@ -438,8 +435,6 @@ proxy_create(struct wl_proxy *factory, const struct wl_interface *interface,
return NULL;
}
- wl_list_insert(&proxy->queue->proxy_list, &proxy->queue_link);
-
return proxy;
}
@@ -499,8 +494,6 @@ wl_proxy_create_for_id(struct wl_proxy *factory,
return NULL;
}
- wl_list_insert(&proxy->queue->proxy_list, &proxy->queue_link);
-
return proxy;
}
@@ -525,9 +518,6 @@ proxy_destroy(struct wl_proxy *proxy)
proxy->flags |= WL_PROXY_FLAG_DESTROYED;
- wl_list_remove(&proxy->queue_link);
- wl_list_init(&proxy->queue_link);
-
wl_proxy_unref(proxy);
}
@@ -2346,8 +2336,6 @@ wl_proxy_set_queue(struct wl_proxy *proxy, struct wl_event_queue *queue)
{
pthread_mutex_lock(&proxy->display->mutex);
- wl_list_remove(&proxy->queue_link);
-
if (queue) {
assert(proxy->display == queue->display);
proxy->queue = queue;
@@ -2355,8 +2343,6 @@ wl_proxy_set_queue(struct wl_proxy *proxy, struct wl_event_queue *queue)
proxy->queue = &proxy->display->default_queue;
}
- wl_list_insert(&proxy->queue->proxy_list, &proxy->queue_link);
-
pthread_mutex_unlock(&proxy->display->mutex);
}
@@ -2428,8 +2414,6 @@ 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);
-
pthread_mutex_unlock(&wrapped_proxy->display->mutex);
return wrapper;
@@ -2451,12 +2435,6 @@ wl_proxy_wrapper_destroy(void *proxy_wrapper)
assert(wrapper->refcount == 1);
- pthread_mutex_lock(&wrapper->display->mutex);
-
- wl_list_remove(&wrapper->queue_link);
-
- pthread_mutex_unlock(&wrapper->display->mutex);
-
free(wrapper);
}
--
2.17.1

View File

@ -0,0 +1,795 @@
From 223d1f32861e21bf9827b813659fbe46c97d8e66 Mon Sep 17 00:00:00 2001
From: Erik Chen <erikchen@chromium.org>
Date: Thu, 20 Oct 2022 00:06:01 +0000
Subject: [PATCH 1/5] Apply WIP CL from upstream wayland
This CL provides the capability of dynamically modifying the buffer size.
https://gitlab.freedesktop.org/wayland/wayland/-/commit/0bfcd4c4bef0ddb555c0e9f07cd3ceff81a33313
Note that I am not the author. This CL has been reviewed upstream.
Bug: 1342356
Change-Id: I24f90fb31248a52aa97f1813a5ff9b30157aa350
Upstream-Status: Pending
---
src/connection.c | 303 ++++++++++++++++++++++++++++----------
src/wayland-client.c | 2 +-
src/wayland-private.h | 8 +-
src/wayland-server-core.h | 7 +
src/wayland-server.c | 63 +++++++-
tests/connection-test.c | 46 +++++-
tests/display-test.c | 5 +-
tests/os-wrappers-test.c | 6 +-
8 files changed, 350 insertions(+), 90 deletions(-)
diff --git a/src/connection.c b/src/connection.c
index ceaeac1..bc6d730 100644
--- a/src/connection.c
+++ b/src/connection.c
@@ -55,12 +55,12 @@ div_roundup(uint32_t n, size_t a)
}
struct wl_ring_buffer {
- char data[4096];
- uint32_t head, tail;
+ char *data;
+ size_t head, tail;
+ uint32_t size_bits;
+ uint32_t max_size_bits; /* 0 for unlimited */
};
-#define MASK(i) ((i) & 4095)
-
#define MAX_FDS_OUT 28
#define CLEN (CMSG_LEN(MAX_FDS_OUT * sizeof(int32_t)))
@@ -71,23 +71,27 @@ struct wl_connection {
int want_flush;
};
+static size_t
+ring_buffer_space(const struct wl_ring_buffer *b) {
+ return ((size_t)1) << b->size_bits;
+}
+
+static size_t
+ring_buffer_mask(const struct wl_ring_buffer *b, size_t i) {
+ size_t m = (((size_t)1) << b->size_bits) - 1;
+ return i & m;
+}
+
static int
ring_buffer_put(struct wl_ring_buffer *b, const void *data, size_t count)
{
- uint32_t head, size;
+ size_t head, size;
- if (count > sizeof(b->data)) {
- wl_log("Data too big for buffer (%d > %d).\n",
- count, sizeof(b->data));
- errno = E2BIG;
- return -1;
- }
-
- head = MASK(b->head);
- if (head + count <= sizeof b->data) {
+ head = ring_buffer_mask(b, b->head);
+ if (head + count <= ring_buffer_space(b)) {
memcpy(b->data + head, data, count);
} else {
- size = sizeof b->data - head;
+ size = ring_buffer_space(b) - head;
memcpy(b->data + head, data, size);
memcpy(b->data, (const char *) data + size, count - size);
}
@@ -100,21 +104,21 @@ ring_buffer_put(struct wl_ring_buffer *b, const void *data, size_t count)
static void
ring_buffer_put_iov(struct wl_ring_buffer *b, struct iovec *iov, int *count)
{
- uint32_t head, tail;
+ size_t head, tail;
- head = MASK(b->head);
- tail = MASK(b->tail);
+ head = ring_buffer_mask(b, b->head);
+ tail = ring_buffer_mask(b, b->tail);
if (head < tail) {
iov[0].iov_base = b->data + head;
iov[0].iov_len = tail - head;
*count = 1;
} else if (tail == 0) {
iov[0].iov_base = b->data + head;
- iov[0].iov_len = sizeof b->data - head;
+ iov[0].iov_len = ring_buffer_space(b) - head;
*count = 1;
} else {
iov[0].iov_base = b->data + head;
- iov[0].iov_len = sizeof b->data - head;
+ iov[0].iov_len = ring_buffer_space(b) - head;
iov[1].iov_base = b->data;
iov[1].iov_len = tail;
*count = 2;
@@ -124,21 +128,21 @@ ring_buffer_put_iov(struct wl_ring_buffer *b, struct iovec *iov, int *count)
static void
ring_buffer_get_iov(struct wl_ring_buffer *b, struct iovec *iov, int *count)
{
- uint32_t head, tail;
+ size_t head, tail;
- head = MASK(b->head);
- tail = MASK(b->tail);
+ head = ring_buffer_mask(b, b->head);
+ tail = ring_buffer_mask(b, b->tail);
if (tail < head) {
iov[0].iov_base = b->data + tail;
iov[0].iov_len = head - tail;
*count = 1;
} else if (head == 0) {
iov[0].iov_base = b->data + tail;
- iov[0].iov_len = sizeof b->data - tail;
+ iov[0].iov_len = ring_buffer_space(b) - tail;
*count = 1;
} else {
iov[0].iov_base = b->data + tail;
- iov[0].iov_len = sizeof b->data - tail;
+ iov[0].iov_len = ring_buffer_space(b) - tail;
iov[1].iov_base = b->data;
iov[1].iov_len = head;
*count = 2;
@@ -148,26 +152,136 @@ ring_buffer_get_iov(struct wl_ring_buffer *b, struct iovec *iov, int *count)
static void
ring_buffer_copy(struct wl_ring_buffer *b, void *data, size_t count)
{
- uint32_t tail, size;
+ size_t tail, size;
- tail = MASK(b->tail);
- if (tail + count <= sizeof b->data) {
+ tail = ring_buffer_mask(b, b->tail);
+ if (tail + count <= ring_buffer_space(b)) {
memcpy(data, b->data + tail, count);
} else {
- size = sizeof b->data - tail;
+ size = ring_buffer_space(b) - tail;
memcpy(data, b->data + tail, size);
memcpy((char *) data + size, b->data, count - size);
}
}
-static uint32_t
+static size_t
ring_buffer_size(struct wl_ring_buffer *b)
{
return b->head - b->tail;
}
+static uint32_t
+get_max_size_bits_for_size(size_t buffer_size)
+{
+ uint32_t max_size_bits = WL_BUFFER_DEFAULT_SIZE_POT;
+
+ /* buffer_size == 0 means unbound buffer size */
+ if (buffer_size == 0)
+ return 0;
+
+ do {
+ if (buffer_size <= (((size_t)1) << max_size_bits))
+ break;
+ } while (max_size_bits++ < (8 * sizeof(size_t) - 1));
+
+ return max_size_bits;
+}
+
+static int
+ring_buffer_allocate(struct wl_ring_buffer *b, size_t size_bits)
+{
+ char *new_data;
+
+ new_data = calloc(((size_t)1) << size_bits, 1);
+ if (!new_data) {
+ errno = ENOMEM;
+ return -1;
+ }
+
+ ring_buffer_copy(b, new_data, ring_buffer_size(b));
+ free(b->data);
+ b->data = new_data;
+ b->size_bits = size_bits;
+ b->head = ring_buffer_size(b);
+ b->tail = 0;
+
+ return 0;
+}
+
+static size_t
+ring_buffer_get_bits_for_size(struct wl_ring_buffer *b, size_t count)
+{
+ size_t net_size = ring_buffer_size(b) + count;
+ size_t max_size_bits = get_max_size_bits_for_size(net_size);
+
+ if (max_size_bits < WL_BUFFER_DEFAULT_SIZE_POT)
+ max_size_bits = WL_BUFFER_DEFAULT_SIZE_POT;
+
+ if (b->max_size_bits > 0 && max_size_bits > b->max_size_bits)
+ max_size_bits = b->max_size_bits;
+
+ return max_size_bits;
+}
+
+static int
+ring_buffer_check_space(struct wl_ring_buffer *b, size_t count)
+{
+ if (ring_buffer_size(b) + count > ring_buffer_space(b)) {
+ wl_log("Data too big for buffer (%d + %zd > %zd).\n",
+ ring_buffer_size(b), count, ring_buffer_space(b));
+ errno = E2BIG;
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+ring_buffer_ensure_space(struct wl_ring_buffer *b, size_t count)
+{
+ size_t size_bits = ring_buffer_get_bits_for_size(b, count);
+ size_t net_size = ring_buffer_size(b) + count;
+
+ if (b->data == NULL)
+ return ring_buffer_allocate(b, size_bits);
+
+ /* Do not shrink (reallocate) if net size won't fit */
+ if (net_size >= (((size_t)1) << size_bits) || b->size_bits == size_bits)
+ return ring_buffer_check_space(b, count);
+
+ if (ring_buffer_allocate(b, size_bits) < 0)
+ return -1;
+
+ return ring_buffer_check_space(b, count);
+}
+
+void
+wl_connection_set_max_buffer_size(struct wl_connection *connection,
+ size_t max_buffer_size)
+{
+ uint32_t max_size_bits;
+
+ max_size_bits = get_max_size_bits_for_size(max_buffer_size);
+
+ connection->fds_in.size_bits = WL_BUFFER_DEFAULT_SIZE_POT;
+ connection->fds_in.max_size_bits = max_size_bits;
+ ring_buffer_ensure_space(&connection->fds_in, 0);
+
+ connection->fds_out.size_bits = WL_BUFFER_DEFAULT_SIZE_POT;
+ connection->fds_out.max_size_bits = max_size_bits;
+ ring_buffer_ensure_space(&connection->fds_out, 0);
+
+ connection->in.size_bits = WL_BUFFER_DEFAULT_SIZE_POT;
+ connection->in.max_size_bits = max_size_bits;
+ ring_buffer_ensure_space(&connection->in, 0);
+
+ connection->out.size_bits = WL_BUFFER_DEFAULT_SIZE_POT;
+ connection->out.max_size_bits = max_size_bits;
+ ring_buffer_ensure_space(&connection->out, 0);
+}
+
struct wl_connection *
-wl_connection_create(int fd)
+wl_connection_create(int fd, size_t max_buffer_size)
{
struct wl_connection *connection;
@@ -175,6 +289,8 @@ wl_connection_create(int fd)
if (connection == NULL)
return NULL;
+ wl_connection_set_max_buffer_size(connection, max_buffer_size);
+
connection->fd = fd;
return connection;
@@ -183,20 +299,28 @@ wl_connection_create(int fd)
static void
close_fds(struct wl_ring_buffer *buffer, int max)
{
- int32_t fds[sizeof(buffer->data) / sizeof(int32_t)], i, count;
- size_t size;
+ size_t size, tail, space;
+ int32_t i, count, *p;
size = ring_buffer_size(buffer);
if (size == 0)
return;
- ring_buffer_copy(buffer, fds, size);
- count = size / sizeof fds[0];
+ count = size / sizeof(int32_t);
if (max > 0 && max < count)
count = max;
- size = count * sizeof fds[0];
- for (i = 0; i < count; i++)
- close(fds[i]);
+
+ tail = ring_buffer_mask(buffer, buffer->tail);
+ space = ring_buffer_space(buffer);
+
+ p = (int32_t *) (buffer->data + tail);
+ for (i = 0; i < count; i++) {
+ if (p >= (int32_t *) (buffer->data + space))
+ p = (int32_t *) buffer->data;
+ close(*p++);
+ }
+
+ size = count * sizeof(int32_t);
buffer->tail += size;
}
@@ -213,6 +337,10 @@ wl_connection_destroy(struct wl_connection *connection)
close_fds(&connection->fds_out, -1);
close_fds(&connection->fds_in, -1);
+ free(connection->fds_in.data);
+ free(connection->fds_out.data);
+ free(connection->in.data);
+ free(connection->out.data);
free(connection);
return fd;
@@ -256,7 +384,7 @@ static int
decode_cmsg(struct wl_ring_buffer *buffer, struct msghdr *msg)
{
struct cmsghdr *cmsg;
- size_t size, max, i;
+ size_t size, i;
int overflow = 0;
for (cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL;
@@ -266,8 +394,8 @@ decode_cmsg(struct wl_ring_buffer *buffer, struct msghdr *msg)
continue;
size = cmsg->cmsg_len - CMSG_LEN(0);
- max = sizeof(buffer->data) - ring_buffer_size(buffer);
- if (size > max || overflow) {
+
+ if (ring_buffer_ensure_space(buffer, size) < 0 || overflow) {
overflow = 1;
size /= sizeof(int32_t);
for (i = 0; i < size; i++)
@@ -293,17 +421,30 @@ wl_connection_flush(struct wl_connection *connection)
char cmsg[CLEN];
int len = 0, count;
size_t clen;
- uint32_t tail;
+ size_t tail;
if (!connection->want_flush)
return 0;
tail = connection->out.tail;
while (connection->out.head - connection->out.tail > 0) {
- ring_buffer_get_iov(&connection->out, iov, &count);
-
build_cmsg(&connection->fds_out, cmsg, &clen);
+ if (clen >= CMSG_LEN(MAX_FDS_OUT * sizeof(int32_t))) {
+ /* Send only a single byte, to ensure all FDs are sent
+ * before the bytes are cleared out. This can fail to
+ * clear the FDs first if individual messages are allowed to
+ * have 8*28 = 224 fds. */
+ iov[0].iov_base = connection->out.data +
+ ring_buffer_mask(&connection->out, connection->out.tail);
+ iov[0].iov_len = 1;
+ count = 1;
+ } else {
+ ring_buffer_get_iov(&connection->out, iov, &count);
+ }
+
+ msg.msg_name = NULL;
+ msg.msg_namelen = 0;
msg.msg_iov = iov;
msg.msg_iovlen = count;
msg.msg_control = (clen > 0) ? cmsg : NULL;
@@ -341,49 +482,49 @@ wl_connection_read(struct wl_connection *connection)
char cmsg[CLEN];
int len, count, ret;
- if (ring_buffer_size(&connection->in) >= sizeof(connection->in.data)) {
- errno = EOVERFLOW;
- return -1;
- }
+ while (1) {
+ int data_size = ring_buffer_size(&connection->in);
+ size_t size_bits = ring_buffer_get_bits_for_size(&connection->in, 1);
- ring_buffer_put_iov(&connection->in, iov, &count);
+ // stop once we've read the max buffer size
+ if (data_size >= (1 << size_bits))
+ return data_size;
+ if (ring_buffer_ensure_space(&connection->in, 1) < 0)
+ return -1;
- msg.msg_name = NULL;
- msg.msg_namelen = 0;
- msg.msg_iov = iov;
- msg.msg_iovlen = count;
- msg.msg_control = cmsg;
- msg.msg_controllen = sizeof cmsg;
- msg.msg_flags = 0;
+ ring_buffer_put_iov(&connection->in, iov, &count);
- do {
- len = wl_os_recvmsg_cloexec(connection->fd, &msg, MSG_DONTWAIT);
- } while (len < 0 && errno == EINTR);
+ msg.msg_name = NULL;
+ msg.msg_namelen = 0;
+ msg.msg_iov = iov;
+ msg.msg_iovlen = count;
+ msg.msg_control = cmsg;
+ msg.msg_controllen = sizeof cmsg;
+ msg.msg_flags = 0;
- if (len <= 0)
- return len;
+ do {
+ len = wl_os_recvmsg_cloexec(connection->fd, &msg, MSG_DONTWAIT);
+ } while (len < 0 && errno == EINTR);
- ret = decode_cmsg(&connection->fds_in, &msg);
- if (ret)
- return -1;
+ if (len < 0 && errno != EAGAIN) {
+ return -1;
+ } else if (len <= 0) {
+ return (data_size > 0) ? data_size : len;
+ }
- connection->in.head += len;
+ ret = decode_cmsg(&connection->fds_in, &msg);
+ if (ret)
+ return -1;
- return wl_connection_pending_input(connection);
+ connection->in.head += len;
+ }
}
int
wl_connection_write(struct wl_connection *connection,
const void *data, size_t count)
{
- if (connection->out.head - connection->out.tail +
- count > ARRAY_LENGTH(connection->out.data)) {
- connection->want_flush = 1;
- if (wl_connection_flush(connection) < 0)
- return -1;
- }
-
- if (ring_buffer_put(&connection->out, data, count) < 0)
+ if (wl_connection_queue(connection, data, count) < 0)
return -1;
connection->want_flush = 1;
@@ -396,12 +537,15 @@ wl_connection_queue(struct wl_connection *connection,
const void *data, size_t count)
{
if (connection->out.head - connection->out.tail +
- count > ARRAY_LENGTH(connection->out.data)) {
+ count > WL_BUFFER_DEFAULT_MAX_SIZE) {
connection->want_flush = 1;
- if (wl_connection_flush(connection) < 0)
+ if (wl_connection_flush(connection) < 0 && errno != EAGAIN)
return -1;
}
+ if (ring_buffer_ensure_space(&connection->out, count) < 0)
+ return -1;
+
return ring_buffer_put(&connection->out, data, count);
}
@@ -427,12 +571,15 @@ wl_connection_get_fd(struct wl_connection *connection)
static int
wl_connection_put_fd(struct wl_connection *connection, int32_t fd)
{
- if (ring_buffer_size(&connection->fds_out) == MAX_FDS_OUT * sizeof fd) {
+ if (ring_buffer_size(&connection->fds_out) >= MAX_FDS_OUT * sizeof fd) {
connection->want_flush = 1;
- if (wl_connection_flush(connection) < 0)
+ if (wl_connection_flush(connection) < 0 && errno != EAGAIN)
return -1;
}
+ if (ring_buffer_ensure_space(&connection->fds_out, sizeof fd) < 0)
+ return -1;
+
return ring_buffer_put(&connection->fds_out, &fd, sizeof fd);
}
diff --git a/src/wayland-client.c b/src/wayland-client.c
index b57bfe9..895d7b8 100644
--- a/src/wayland-client.c
+++ b/src/wayland-client.c
@@ -1198,7 +1198,7 @@ wl_display_connect_to_fd(int fd)
*/
display->proxy.version = 0;
- display->connection = wl_connection_create(display->fd);
+ display->connection = wl_connection_create(display->fd, 0);
if (display->connection == NULL)
goto err_connection;
diff --git a/src/wayland-private.h b/src/wayland-private.h
index 9274f1b..a3a5032 100644
--- a/src/wayland-private.h
+++ b/src/wayland-private.h
@@ -47,6 +47,8 @@
#define WL_SERVER_ID_START 0xff000000
#define WL_MAP_MAX_OBJECTS 0x00f00000
#define WL_CLOSURE_MAX_ARGS 20
+#define WL_BUFFER_DEFAULT_SIZE_POT 12
+#define WL_BUFFER_DEFAULT_MAX_SIZE (1 << WL_BUFFER_DEFAULT_SIZE_POT)
struct wl_object {
const struct wl_interface *interface;
@@ -106,7 +108,7 @@ void
wl_map_for_each(struct wl_map *map, wl_iterator_func_t func, void *data);
struct wl_connection *
-wl_connection_create(int fd);
+wl_connection_create(int fd, size_t max_buffer_size);
int
wl_connection_destroy(struct wl_connection *connection);
@@ -237,4 +239,8 @@ zalloc(size_t s)
void
wl_connection_close_fds_in(struct wl_connection *connection, int max);
+void
+wl_connection_set_max_buffer_size(struct wl_connection *connection,
+ size_t max_buffer_size);
+
#endif
diff --git a/src/wayland-server-core.h b/src/wayland-server-core.h
index df95821..15ee498 100644
--- a/src/wayland-server-core.h
+++ b/src/wayland-server-core.h
@@ -217,6 +217,10 @@ wl_display_flush_clients(struct wl_display *display);
void
wl_display_destroy_clients(struct wl_display *display);
+void
+wl_display_set_default_max_buffer_size(struct wl_display *display,
+ size_t max_buffer_size);
+
struct wl_client;
typedef void (*wl_global_bind_func_t)(struct wl_client *client, void *data,
@@ -365,6 +369,9 @@ wl_client_for_each_resource(struct wl_client *client,
wl_client_for_each_resource_iterator_func_t iterator,
void *user_data);
+void
+wl_client_set_max_buffer_size(struct wl_client *client, size_t max_buffer_size);
+
/** \class wl_listener
*
* \brief A single listener for Wayland signals
diff --git a/src/wayland-server.c b/src/wayland-server.c
index d51acc6..166a065 100644
--- a/src/wayland-server.c
+++ b/src/wayland-server.c
@@ -110,6 +110,8 @@ struct wl_display {
int terminate_efd;
struct wl_event_source *term_source;
+
+ size_t max_buffer_size;
};
struct wl_global {
@@ -538,7 +540,8 @@ wl_client_create(struct wl_display *display, int fd)
&client->pid) != 0)
goto err_source;
- client->connection = wl_connection_create(fd);
+ client->connection = wl_connection_create(fd, display->max_buffer_size);
+
if (client->connection == NULL)
goto err_source;
@@ -1144,6 +1147,7 @@ wl_display_create(void)
display->global_filter = NULL;
display->global_filter_data = NULL;
+ display->max_buffer_size = WL_BUFFER_DEFAULT_MAX_SIZE;
wl_array_init(&display->additional_shm_formats);
@@ -1550,6 +1554,36 @@ wl_display_destroy_clients(struct wl_display *display)
}
}
+/** Sets the default maximum size for connection buffers of new clients
+ *
+ * \param display The display object
+ * \param max_buffer_size The default maximum size of the connection buffers
+ *
+ * This function sets the default size of the internal connection buffers for
+ * new clients, it doesn't change the buffer size for existing wl_client.
+ *
+ * The connection buffer size of each existing wl_client can be adjusted using
+ * wl_client_set_max_buffer_size().
+ *
+ * The actual size of the connection buffers is a power of two, the requested
+ * \a max_buffer_size is therefore rounded up to the nearest power of two value.
+ *
+ * The minimum buffer size is 4096.
+ *
+ * \sa wl_client_set_max_buffer_size
+ *
+ * \memberof wl_display
+ */
+WL_EXPORT void
+wl_display_set_default_max_buffer_size(struct wl_display *display,
+ size_t max_buffer_size)
+{
+ if (max_buffer_size < WL_BUFFER_DEFAULT_MAX_SIZE)
+ max_buffer_size = WL_BUFFER_DEFAULT_MAX_SIZE;
+
+ display->max_buffer_size = max_buffer_size;
+}
+
static int
socket_data(int fd, uint32_t mask, void *data)
{
@@ -2245,6 +2279,33 @@ wl_signal_emit_mutable(struct wl_signal *signal, void *data)
wl_list_remove(&end.link);
}
+/** Adjust the maximum size of the client connection buffers
+ *
+ * \param client The client object
+ * \param max_buffer_size The maximum size of the connection buffers
+ *
+ * The actual size of the connection buffers is a power of two, the requested
+ * \a max_buffer_size is therefore rounded up to the nearest power of two value.
+ *
+ * Lowering the maximum size may not take effect immediately if the current content
+ * of the buffer does not fit within the new size limit.
+ *
+ * The minimum buffer size is 4096. The default buffers size can be set using
+ * wl_display_set_default_max_buffer_size()
+ *
+ * \sa wl_display_set_default_max_buffer_size()
+ *
+ * \memberof wl_client
+ */
+WL_EXPORT void
+wl_client_set_max_buffer_size(struct wl_client *client, size_t max_buffer_size)
+{
+ if (max_buffer_size < WL_BUFFER_DEFAULT_MAX_SIZE)
+ max_buffer_size = WL_BUFFER_DEFAULT_MAX_SIZE;
+
+ wl_connection_set_max_buffer_size(client->connection, max_buffer_size);
+}
+
/** \cond INTERNAL */
/** Initialize a wl_priv_signal object
diff --git a/tests/connection-test.c b/tests/connection-test.c
index 9762e0d..0c76045 100644
--- a/tests/connection-test.c
+++ b/tests/connection-test.c
@@ -50,7 +50,7 @@ setup(int *s)
assert(socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, s) == 0);
- connection = wl_connection_create(s[0]);
+ connection = wl_connection_create(s[0], WL_BUFFER_DEFAULT_MAX_SIZE);
assert(connection);
return connection;
@@ -183,9 +183,11 @@ setup_marshal_data(struct marshal_data *data)
{
assert(socketpair(AF_UNIX,
SOCK_STREAM | SOCK_CLOEXEC, 0, data->s) == 0);
- data->read_connection = wl_connection_create(data->s[0]);
+ data->read_connection = wl_connection_create(data->s[0],
+ WL_BUFFER_DEFAULT_MAX_SIZE);
assert(data->read_connection);
- data->write_connection = wl_connection_create(data->s[1]);
+ data->write_connection = wl_connection_create(data->s[1],
+ WL_BUFFER_DEFAULT_MAX_SIZE);
assert(data->write_connection);
}
@@ -277,6 +279,25 @@ expected_fail_marshal(int expected_error, const char *format, ...)
assert(errno == expected_error);
}
+static void
+marshal_send(struct marshal_data *data, const char *format, ...)
+{
+ struct wl_closure *closure;
+ static const uint32_t opcode = 4444;
+ static struct wl_object sender = { NULL, NULL, 1234 };
+ struct wl_message message = { "test", format, NULL };
+ va_list ap;
+
+ va_start(ap, format);
+ closure = wl_closure_vmarshal(&sender, opcode, ap, &message);
+ va_end(ap);
+
+ assert(closure);
+ assert(wl_closure_send(closure, data->write_connection) == 0);
+
+ wl_closure_destroy(closure);
+}
+
static void
expected_fail_marshal_send(struct marshal_data *data, int expected_error,
const char *format, ...)
@@ -644,6 +665,25 @@ TEST(connection_marshal_too_big)
free(big_string);
}
+TEST(connection_marshal_big_enough)
+{
+ struct marshal_data data;
+ char *big_string = malloc(5000);
+
+ assert(big_string);
+
+ memset(big_string, ' ', 4999);
+ big_string[4999] = '\0';
+
+ setup_marshal_data(&data);
+ wl_connection_set_max_buffer_size(data.write_connection, 5120);
+
+ marshal_send(&data, "s", big_string);
+
+ release_marshal_data(&data);
+ free(big_string);
+}
+
static void
marshal_helper(const char *format, void *handler, ...)
{
diff --git a/tests/display-test.c b/tests/display-test.c
index bcb3267..6fc136d 100644
--- a/tests/display-test.c
+++ b/tests/display-test.c
@@ -1513,10 +1513,7 @@ send_overflow_client(void *data)
/* Do not close the pipe file descriptors afterwards, because the leak
* check verifies that the initial/final FD counts are the same */
assert(write(pipes[1], &tmp, sizeof(tmp)) == (ssize_t)sizeof(tmp));
-
- /* Expect an error */
- fprintf(stderr, "Send loop failed on try %d, err = %d, %s\n", i, err, strerror(err));
- assert(err == EAGAIN);
+ assert(err == 0);
client_disconnect_nocheck(c);
}
diff --git a/tests/os-wrappers-test.c b/tests/os-wrappers-test.c
index 8d8c3ab..e65a5d6 100644
--- a/tests/os-wrappers-test.c
+++ b/tests/os-wrappers-test.c
@@ -256,10 +256,12 @@ setup_marshal_data(struct marshal_data *data)
assert(socketpair(AF_UNIX,
SOCK_STREAM | SOCK_CLOEXEC, 0, data->s) == 0);
- data->read_connection = wl_connection_create(data->s[0]);
+ data->read_connection = wl_connection_create(data->s[0],
+ WL_BUFFER_DEFAULT_MAX_SIZE);
assert(data->read_connection);
- data->write_connection = wl_connection_create(data->s[1]);
+ data->write_connection = wl_connection_create(data->s[1],
+ WL_BUFFER_DEFAULT_MAX_SIZE);
assert(data->write_connection);
}
--
2.17.1

View File

@ -0,0 +1,45 @@
From 191eeb6f2ed6429b16db053b45f0fa81df55329d Mon Sep 17 00:00:00 2001
From: Erik Chen <erikchen@chromium.org>
Date: Sun, 30 Oct 2022 23:31:57 +0000
Subject: [PATCH 2/5] Set the default max buffer size to unbounded.
Bug: 1342356
Change-Id: I6e6c353504d6817b9bf76bc7e8b24001d7957ad6
Upstream-Status: Pending
---
src/connection.c | 2 +-
src/wayland-private.h | 5 ++++-
2 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/src/connection.c b/src/connection.c
index bc6d730..2b3c7e4 100644
--- a/src/connection.c
+++ b/src/connection.c
@@ -537,7 +537,7 @@ wl_connection_queue(struct wl_connection *connection,
const void *data, size_t count)
{
if (connection->out.head - connection->out.tail +
- count > WL_BUFFER_DEFAULT_MAX_SIZE) {
+ count > WL_BUFFER_FLUSH_SIZE) {
connection->want_flush = 1;
if (wl_connection_flush(connection) < 0 && errno != EAGAIN)
return -1;
diff --git a/src/wayland-private.h b/src/wayland-private.h
index a3a5032..1aafa2e 100644
--- a/src/wayland-private.h
+++ b/src/wayland-private.h
@@ -48,7 +48,10 @@
#define WL_MAP_MAX_OBJECTS 0x00f00000
#define WL_CLOSURE_MAX_ARGS 20
#define WL_BUFFER_DEFAULT_SIZE_POT 12
-#define WL_BUFFER_DEFAULT_MAX_SIZE (1 << WL_BUFFER_DEFAULT_SIZE_POT)
+// 0 means unbounded.
+#define WL_BUFFER_DEFAULT_MAX_SIZE 0
+// The size at which queueing a request will also trigger a flush.
+#define WL_BUFFER_FLUSH_SIZE (1 << WL_BUFFER_DEFAULT_SIZE_POT)
struct wl_object {
const struct wl_interface *interface;
--
2.17.1

View File

@ -0,0 +1,43 @@
From 47a912b7a20d689da5a9e1fb848a616822de8b60 Mon Sep 17 00:00:00 2001
From: Kramer Ge <fangzhoug@chromium.org>
Date: Wed, 19 Jul 2023 14:46:56 -0400
Subject: [PATCH 3/5] Log the object and methods when marshalling or sending
fails.
The log that appears before a display_error will be captured as crash
signature.
Bug: 1451333
Change-Id: I06a0a1294c5431d0f8261e522aaa469e2c427725
Upstream-Status: Pending
---
src/wayland-client.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/src/wayland-client.c b/src/wayland-client.c
index 895d7b8..451c035 100644
--- a/src/wayland-client.c
+++ b/src/wayland-client.c
@@ -848,7 +848,8 @@ wl_proxy_marshal_array_flags(struct wl_proxy *proxy, uint32_t opcode,
closure = wl_closure_marshal(&proxy->object, opcode, args, message);
if (closure == NULL) {
- wl_log("Error marshalling request: %s\n", strerror(errno));
+ wl_log("Error marshalling request for %s.%s: %s\n",
+ proxy->object.interface->name, message->name, strerror(errno));
display_fatal_error(proxy->display, errno);
goto err_unlock;
}
@@ -857,7 +858,8 @@ wl_proxy_marshal_array_flags(struct wl_proxy *proxy, uint32_t opcode,
wl_closure_print(closure, &proxy->object, true, false, NULL);
if (wl_closure_send(closure, proxy->display->connection)) {
- wl_log("Error sending request: %s\n", strerror(errno));
+ wl_log("Error sending request for %s.%s: %s\n",
+ proxy->object.interface->name, message->name, strerror(errno));
display_fatal_error(proxy->display, errno);
}
--
2.17.1

View File

@ -0,0 +1,121 @@
From 3806c948b5e3af1e13383ce3b24b0cebfde0a721 Mon Sep 17 00:00:00 2001
From: Thomas Lukaszewicz <tluk@chromium.org>
Date: Fri, 21 Jul 2023 23:28:12 +0000
Subject: [PATCH 4/5] Fix buffer resize crash
Currently chromium wayland clients can crash if a connection buffer
(which is initialized at a capacity of 2^12) is asked to resize
exactly at its resize threshold. This threshold is in steps of
powers of 2.
Take net_size to be the size the connection buffer is required to
support for the current outbound request queue.
This is crash due to certain parts of the code assuming that
net_size can exactly match the capacity of the connection buffer,
while other parts of the code assume the capacity of the buffer
must exceed the net_size. The latter assumption is the root cause
of the crash.
Specifically:
1. ring_buffer_ensure_space() attempts to find the new buffer
`size_bits` required to contain the new `net_size` of the
request buffer [1]
2. This eventually calls into get_max_size_bits_for_size()
which finds the `size_bits` required for `net_size`[2]
- This code assumes that `net_size <= 2^size_bits` in order
to fit the data
3. Back in ring_buffer_ensure_space() the `size_bits` returned
is checked to ensure it can contain `net_size` and if a
resize is needed.
- This code assumes that `net_size < 2^size_bits` in order
to fit the data [3]
- If a resize is not needed, the buffer is checked
whether it can hold `net_size` without resizing and a
crash occurs [4]
The assumptions about buffer capacity differ in 2 and 3, and the
assertion in 3 causes the crash in the associated bug. This only
occurs when `net_size == 2^size_bits` which satisfies the condition
in 2 but fails the condition in 3.
In Lacros code there were a set of users encountering this crash
when buffers were being asked to resize when clients made the
zwp_text_input_v1_set_surrounding_text() with large blocks of
text (typically from a ssh session).
This CL enforces the requirement that the connection buffer must
be greater than the net_size.
For more context see below.
https://gitlab.freedesktop.org/wayland/wayland/-/merge_requests/188#note_2010874
[1] https://chromium.googlesource.com/external/anongit.freedesktop.org/git/wayland/wayland/+/refs/heads/chromium_1_21_0/src/connection.c#242
[2] https://chromium.googlesource.com/external/anongit.freedesktop.org/git/wayland/wayland/+/refs/heads/chromium_1_21_0/src/connection.c#183
[3] https://chromium.googlesource.com/external/anongit.freedesktop.org/git/wayland/wayland/+/refs/heads/chromium_1_21_0/src/connection.c#249
[4] https://chromium.googlesource.com/external/anongit.freedesktop.org/git/wayland/wayland/+/refs/heads/chromium_1_21_0/src/connection.c#229
Bug: 1451333
Change-Id: I87853e3ff26c1d693f199fd0045fef796c3730c9
Upstream-Status: Pending
---
src/connection.c | 2 +-
tests/connection-test.c | 26 ++++++++++++++++++++++++++
2 files changed, 27 insertions(+), 1 deletion(-)
diff --git a/src/connection.c b/src/connection.c
index 2b3c7e4..bea4714 100644
--- a/src/connection.c
+++ b/src/connection.c
@@ -180,7 +180,7 @@ get_max_size_bits_for_size(size_t buffer_size)
return 0;
do {
- if (buffer_size <= (((size_t)1) << max_size_bits))
+ if (buffer_size < (((size_t)1) << max_size_bits))
break;
} while (max_size_bits++ < (8 * sizeof(size_t) - 1));
diff --git a/tests/connection-test.c b/tests/connection-test.c
index 0c76045..7f64443 100644
--- a/tests/connection-test.c
+++ b/tests/connection-test.c
@@ -684,6 +684,32 @@ TEST(connection_marshal_big_enough)
free(big_string);
}
+/* Ensures that buffers are resiable to accomodate requests for sizes at the
+ * resize threshold (power of 2). Regression test for crbug.com/1451333. */
+TEST(connection_marshal_resize_at_buffer_growth_threshold)
+{
+ /* A string of lenth 8178 requires a buffer size of exactly 2^13.
+ * TODO(tluk): Determine a way to require a resize at 2^13 in a more robust
+ * way */
+ struct marshal_data data;
+ const int kStrSize = 8178;
+ char *big_string = malloc(kStrSize);
+ assert(big_string);
+
+ memset(big_string, ' ', kStrSize-1);
+ big_string[kStrSize-1] = '\0';
+
+ setup_marshal_data(&data);
+
+ /* Set the max size to 0 (unbounded). */
+ wl_connection_set_max_buffer_size(data.write_connection, 0);
+
+ marshal_send(&data, "s", big_string);
+
+ release_marshal_data(&data);
+ free(big_string);
+}
+
static void
marshal_helper(const char *format, void *handler, ...)
{
--
2.17.1

View File

@ -0,0 +1,53 @@
From 603a8330853615f84674c0db86f65c1f1c671163 Mon Sep 17 00:00:00 2001
From: David Benjamin <davidben@google.com>
Date: Wed, 8 Nov 2023 11:51:40 -0500
Subject: [PATCH 5/5] connection: avoid calling memcpy on NULL, 0
This imports
https://gitlab.freedesktop.org/wayland/wayland/-/merge_requests/354 from
upstream.
Bug: 1394755
Change-Id: If8f495b6aa70871920de9f66a1f1600dce917a10
Upstream-Status: Pending
---
src/connection.c | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/src/connection.c b/src/connection.c
index bea4714..2233eb4 100644
--- a/src/connection.c
+++ b/src/connection.c
@@ -87,6 +87,9 @@ ring_buffer_put(struct wl_ring_buffer *b, const void *data, size_t count)
{
size_t head, size;
+ if (count == 0)
+ return 0;
+
head = ring_buffer_mask(b, b->head);
if (head + count <= ring_buffer_space(b)) {
memcpy(b->data + head, data, count);
@@ -154,6 +157,9 @@ ring_buffer_copy(struct wl_ring_buffer *b, void *data, size_t count)
{
size_t tail, size;
+ if (count == 0)
+ return;
+
tail = ring_buffer_mask(b, b->tail);
if (tail + count <= ring_buffer_space(b)) {
memcpy(data, b->data + tail, count);
@@ -1333,7 +1339,8 @@ serialize_closure(struct wl_closure *closure, uint32_t *buffer,
if (p + div_roundup(size, sizeof *p) > end)
goto overflow;
- memcpy(p, closure->args[i].a->data, size);
+ if (size != 0)
+ memcpy(p, closure->args[i].a->data, size);
p += div_roundup(size, sizeof *p);
break;
default:
--
2.17.1

View File

@ -0,0 +1,13 @@
FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"
SRC_URI:append:imxgpu:arm = " \
file://0101-Revert-client-Do-not-warn-about-attached-proxies-on-.patch \
file://0102-Revert-client-Abort-when-trying-to-add-an-event-to-a.patch \
file://0103-Revert-client-Warn-when-a-queue-is-destroyed-with-at.patch \
file://0104-Revert-client-Track-the-proxies-attached-to-a-queue.patch \
file://0201-Apply-WIP-CL-from-upstream-wayland.patch \
file://0202-Set-the-default-max-buffer-size-to-unbounded.patch \
file://0203-Log-the-object-and-methods-when-marshalling-or-sendi.patch \
file://0204-Fix-buffer-resize-crash.patch \
file://0205-connection-avoid-calling-memcpy-on-NULL-0.patch \
"