[PATCH] Increase closure buffer size and fail gracefully for too big closures.

Laszlo Agocs laszlo.p.agocs at nokia.com
Fri Dec 16 00:29:36 PST 2011


Buffer size changed from 256 to 1024 bytes. Marshalling will now
calculate the total size in advance and will stop if the buffer is not
big enough.
---
 src/connection.c     |   73 +++++++++++++++++++++++++++++++++++++++++++++++--
 src/wayland-client.c |    7 ++++-
 src/wayland-server.c |    6 ++++
 3 files changed, 82 insertions(+), 4 deletions(-)

diff --git a/src/connection.c b/src/connection.c
index f19280a..4acb1a3 100644
--- a/src/connection.c
+++ b/src/connection.c
@@ -54,7 +54,7 @@ struct wl_closure {
 	ffi_type *types[20];
 	ffi_cif cif;
 	void *args[20];
-	uint32_t buffer[64];
+	uint32_t buffer[256];
 	uint32_t *start;
 };
 
@@ -384,6 +384,60 @@ wl_message_size_extra(const struct wl_message *message)
 	return extra;
 }
 
+static int
+wl_message_size(const struct wl_message *message, va_list ap)
+{
+	int i, size, length;
+	const char *s;
+	struct wl_array *array;
+
+	for (i = 0, size = 0; message->signature[i]; i++) {
+
+		switch (message->signature[i]) {
+		case 'u':
+			va_arg(ap, uint32_t);
+			size += sizeof (uint32_t);
+			break;
+
+		case 'i':
+			va_arg(ap, int32_t);
+			size += sizeof (uint32_t);
+			break;
+
+		case 'o':
+			va_arg(ap, struct wl_object *);
+			size += sizeof (uint32_t);
+			break;
+
+		case 'n':
+			va_arg(ap, struct wl_object *);
+			size += sizeof (uint32_t);
+			break;
+
+		case 's':
+			s = va_arg(ap, const char *);
+			length = s ? strlen(s) + 1: 0;
+			size += sizeof (uint32_t) + ALIGN(length, sizeof (uint32_t));
+			break;
+
+		case 'a':
+			array = va_arg(ap, struct wl_array *);
+			length = array ? array->size : 0;
+			size += sizeof (uint32_t) + ALIGN(length, sizeof (uint32_t));
+			break;
+
+		case 'h':
+			va_arg(ap, int);
+			break;
+
+		default:
+			break;
+		}
+	}
+
+	return size + 2 * sizeof (uint32_t);
+}
+
 struct wl_closure *
 wl_connection_vmarshal(struct wl_connection *connection,
 		       struct wl_object *sender,
@@ -397,13 +451,24 @@ wl_connection_vmarshal(struct wl_connection *connection,
 	struct wl_array **arrayp, *array;
 	const char **sp, *s;
 	char *extra;
-	int i, count, fd, extra_size, *fd_ptr;
+	int i, count, fd, extra_size, *fd_ptr, total_size;
+	va_list size_ap;
 
 	extra_size = wl_message_size_extra(message);
 	count = strlen(message->signature) + 2;
 	extra = (char *) closure->buffer;
 	start = &closure->buffer[DIV_ROUNDUP(extra_size, sizeof *p)];
 	p = &start[2];
+
+	va_copy(size_ap, ap);
+	total_size = wl_message_size(message, size_ap) + ALIGN(extra_size, sizeof(*p));
+	if (sizeof closure->buffer < total_size) {
+		printf("request too big to marshal, maximum %d actual %d\n",
+		       sizeof closure->buffer, total_size);
+		errno = ENOMEM;
+		return NULL;
+	}
+
 	for (i = 2; i < count; i++) {
 		switch (message->signature[i - 2]) {
 		case 'u':
@@ -501,6 +566,7 @@ wl_connection_vmarshal(struct wl_connection *connection,
 	}
 
 	size = (p - start) * sizeof *p;
+	assert(size + ALIGN(extra_size, sizeof(*p)) == total_size);
 	start[0] = sender->id;
 	start[1] = opcode | (size << 16);
 
@@ -535,7 +601,8 @@ wl_connection_demarshal(struct wl_connection *connection,
 
 	extra_space = wl_message_size_extra(message);
 	if (sizeof closure->buffer < size + extra_space) {
-		printf("request too big, should malloc tmp buffer here\n");
+		printf("request too big to demarshal, maximum %d actual %d\n",
+		       sizeof closure->buffer, size + extra_space);
 		errno = ENOMEM;
 		wl_connection_consume(connection, size);
 		return NULL;
diff --git a/src/wayland-client.c b/src/wayland-client.c
index e4f2c99..bbfc035 100644
--- a/src/wayland-client.c
+++ b/src/wayland-client.c
@@ -198,6 +198,11 @@ wl_proxy_marshal(struct wl_proxy *proxy, uint32_t opcode, ...)
 					 &proxy->object.interface->methods[opcode]);
 	va_end(ap);
 
+	if (closure == NULL) {
+		fprintf(stderr, "Error marshalling request\n");
+		abort();
+	}
+
 	wl_closure_send(closure, proxy->display->connection);
 
 	if (wl_debug)
@@ -473,7 +478,7 @@ handle_event(struct wl_display *display,
 					  size, &display->objects, message);
 
 	if (closure == NULL) {
-		fprintf(stderr, "Error demarshalling event: %m\n");
+		fprintf(stderr, "Error demarshalling event\n");
 		abort();
 	}
 
diff --git a/src/wayland-server.c b/src/wayland-server.c
index 421c3f0..87e4ed5 100644
--- a/src/wayland-server.c
+++ b/src/wayland-server.c
@@ -100,6 +100,9 @@ wl_resource_post_event(struct wl_resource *resource, uint32_t opcode, ...)
 					 &object->interface->events[opcode]);
 	va_end(ap);
 
+	if (closure == NULL)
+		return;
+
 	wl_closure_send(closure, resource->client->connection);
 
 	if (wl_debug)
@@ -122,6 +125,9 @@ wl_resource_queue_event(struct wl_resource *resource, uint32_t opcode, ...)
 					 &object->interface->events[opcode]);
 	va_end(ap);
 
+	if (closure == NULL)
+		return;
+
 	wl_closure_queue(closure, resource->client->connection);
 
 	if (wl_debug)
-- 
1.7.4.1


--------------030205090908000207040602--


More information about the wayland-devel mailing list