Don't hard code header format

Signed-off-by: Julian Orth <ju.orth@gmail.com>
This commit is contained in:
Julian Orth 2025-09-11 14:04:20 +02:00
parent 264da6a92b
commit 8d54c4e22d
4 changed files with 65 additions and 29 deletions

View file

@ -619,6 +619,28 @@ wl_connection_get_fd(struct wl_connection *connection)
return connection->fd; return connection->fd;
} }
size_t
wl_connection_header_size(struct wl_connection *connection)
{
// Adjust WL_HEADER_MAX_SIZE when increasing this.
return 8;
}
void
wl_connection_parse_header(struct wl_connection *connection,
uint32_t *header,
uint32_t *sender_id,
int *size,
int *opcode)
{
*sender_id = header[0];
uint32_t field2 = header[1];
uint32_t field2_hi = field2 >> 16;
uint32_t field2_lo = field2 & 0xffff;
*size = (int)field2_hi;
*opcode = (int)field2_lo;
}
static int static int
wl_connection_put_fd(struct wl_connection *connection, int32_t fd) wl_connection_put_fd(struct wl_connection *connection, int32_t fd)
{ {
@ -894,14 +916,14 @@ wl_connection_demarshal(struct wl_connection *connection,
uint32_t *p, *next, *end, length, length_in_u32, id; uint32_t *p, *next, *end, length, length_in_u32, id;
int fd; int fd;
char *s; char *s;
int i, count, num_arrays; int i, count, num_arrays, ssize, opcode;
const char *signature; const char *signature;
struct argument_details arg; struct argument_details arg;
struct wl_closure *closure; struct wl_closure *closure;
struct wl_array *array_extra; struct wl_array *array_extra;
/* Space for sender_id and opcode */ /* Space for sender_id and opcode */
if (size < 2 * sizeof *p) { if (size < wl_connection_header_size(connection)) {
wl_log("message too short, invalid header\n"); wl_log("message too short, invalid header\n");
wl_connection_consume(connection, size); wl_connection_consume(connection, size);
errno = EINVAL; errno = EINVAL;
@ -921,8 +943,9 @@ wl_connection_demarshal(struct wl_connection *connection,
end = p + size / sizeof *p; end = p + size / sizeof *p;
wl_connection_copy(connection, p, size); wl_connection_copy(connection, p, size);
closure->sender_id = *p++; wl_connection_parse_header(connection, p, &closure->sender_id, &ssize, &opcode);
closure->opcode = *p++ & 0x0000ffff; closure->opcode = (uint32_t)opcode;
p += wl_connection_header_size(connection) / sizeof *p;
signature = message->signature; signature = message->signature;
for (i = 0; i < count; i++) { for (i = 0; i < count; i++) {
@ -1283,7 +1306,7 @@ copy_fds_to_connection(struct wl_closure *closure,
static uint32_t static uint32_t
buffer_size_for_closure(struct wl_closure *closure) buffer_size_for_closure(struct wl_connection *connection, struct wl_closure *closure)
{ {
const struct wl_message *message = closure->message; const struct wl_message *message = closure->message;
int i, count; int i, count;
@ -1329,23 +1352,24 @@ buffer_size_for_closure(struct wl_closure *closure)
} }
} }
return buffer_size + 2; return buffer_size + wl_connection_header_size(connection) / sizeof(uint32_t);
} }
static int static int
serialize_closure(struct wl_closure *closure, uint32_t *buffer, serialize_closure(struct wl_connection *connection, struct wl_closure *closure,
size_t buffer_count) uint32_t *buffer, size_t buffer_count)
{ {
const struct wl_message *message = closure->message; const struct wl_message *message = closure->message;
unsigned int i, count, size; unsigned int i, count, size;
uint32_t *p, *end; uint32_t *p, *end;
struct argument_details arg; struct argument_details arg;
const char *signature; const char *signature;
uint32_t header_words = wl_connection_header_size(connection) / sizeof(*buffer);
if (buffer_count < 2) if (buffer_count < header_words)
goto overflow; goto overflow;
p = buffer + 2; p = buffer + header_words;
end = buffer + buffer_count; end = buffer + buffer_count;
signature = message->signature; signature = message->signature;
@ -1436,7 +1460,7 @@ wl_closure_send(struct wl_closure *closure, struct wl_connection *connection)
if (copy_fds_to_connection(closure, connection)) if (copy_fds_to_connection(closure, connection))
return -1; return -1;
buffer_size = buffer_size_for_closure(closure); buffer_size = buffer_size_for_closure(connection, closure);
buffer = zalloc(buffer_size * sizeof buffer[0]); buffer = zalloc(buffer_size * sizeof buffer[0]);
if (buffer == NULL) { if (buffer == NULL) {
wl_log("wl_closure_send error: buffer allocation failure of " wl_log("wl_closure_send error: buffer allocation failure of "
@ -1446,7 +1470,7 @@ wl_closure_send(struct wl_closure *closure, struct wl_connection *connection)
return -1; return -1;
} }
size = serialize_closure(closure, buffer, buffer_size); size = serialize_closure(connection, closure, buffer, buffer_size);
if (size < 0) { if (size < 0) {
free(buffer); free(buffer);
return -1; return -1;
@ -1469,7 +1493,7 @@ wl_closure_queue(struct wl_closure *closure, struct wl_connection *connection)
if (copy_fds_to_connection(closure, connection)) if (copy_fds_to_connection(closure, connection))
return -1; return -1;
buffer_size = buffer_size_for_closure(closure); buffer_size = buffer_size_for_closure(connection, closure);
buffer = malloc(buffer_size * sizeof buffer[0]); buffer = malloc(buffer_size * sizeof buffer[0]);
if (buffer == NULL) { if (buffer == NULL) {
wl_log("wl_closure_queue error: buffer allocation failure of " wl_log("wl_closure_queue error: buffer allocation failure of "
@ -1479,7 +1503,7 @@ wl_closure_queue(struct wl_closure *closure, struct wl_connection *connection)
return -1; return -1;
} }
size = serialize_closure(closure, buffer, buffer_size); size = serialize_closure(connection, closure, buffer, buffer_size);
if (size < 0) { if (size < 0) {
free(buffer); free(buffer);
return -1; return -1;

View file

@ -1564,7 +1564,7 @@ increase_closure_args_refcount(struct wl_closure *closure)
static int static int
queue_event(struct wl_display *display, int len) queue_event(struct wl_display *display, int len)
{ {
uint32_t p[2], id; uint32_t p[WL_MAX_HEADER_U32], id;
int opcode, size; int opcode, size;
struct wl_proxy *proxy; struct wl_proxy *proxy;
struct wl_closure *closure; struct wl_closure *closure;
@ -1574,10 +1574,8 @@ queue_event(struct wl_display *display, int len)
unsigned int time; unsigned int time;
int num_zombie_fds; int num_zombie_fds;
wl_connection_copy(display->connection, p, sizeof p); wl_connection_copy(display->connection, p, wl_connection_header_size(display->connection));
id = p[0]; wl_connection_parse_header(display->connection, p, &id, &size, &opcode);
opcode = p[1] & 0xffff;
size = p[1] >> 16;
/* /*
* If the message is larger than the maximum size of the * If the message is larger than the maximum size of the
@ -1736,6 +1734,7 @@ read_events(struct wl_display *display)
{ {
int total, rem, size; int total, rem, size;
uint32_t serial; uint32_t serial;
int header_size = wl_connection_header_size(display->connection);
display->reader_count--; display->reader_count--;
if (display->reader_count == 0) { if (display->reader_count == 0) {
@ -1760,7 +1759,7 @@ read_events(struct wl_display *display)
return -1; return -1;
} }
for (rem = total; rem >= 8; rem -= size) { for (rem = total; rem >= header_size; rem -= size) {
size = queue_event(display, rem); size = queue_event(display, rem);
if (size == -1) { if (size == -1) {
display_fatal_error(display, errno); display_fatal_error(display, errno);

View file

@ -49,6 +49,8 @@
#define WL_CLOSURE_MAX_ARGS 20 #define WL_CLOSURE_MAX_ARGS 20
#define WL_BUFFER_DEFAULT_SIZE_POT 12 #define WL_BUFFER_DEFAULT_SIZE_POT 12
#define WL_BUFFER_DEFAULT_MAX_SIZE (1 << WL_BUFFER_DEFAULT_SIZE_POT) #define WL_BUFFER_DEFAULT_MAX_SIZE (1 << WL_BUFFER_DEFAULT_SIZE_POT)
#define WL_MAX_HEADER_SIZE 8
#define WL_MAX_HEADER_U32 (WL_MAX_HEADER_SIZE / 4)
#if WL_BUFFER_DEFAULT_MAX_SIZE < WL_MAX_MESSAGE_SIZE #if WL_BUFFER_DEFAULT_MAX_SIZE < WL_MAX_MESSAGE_SIZE
# error default buffer cannot hold maximum-sized message # error default buffer cannot hold maximum-sized message
#endif #endif
@ -164,6 +166,16 @@ wl_connection_queue(struct wl_connection *connection,
int int
wl_connection_get_fd(struct wl_connection *connection); wl_connection_get_fd(struct wl_connection *connection);
size_t
wl_connection_header_size(struct wl_connection *connection);
void
wl_connection_parse_header(struct wl_connection *connection,
uint32_t *header,
uint32_t *sender_id,
int *size,
int *opcode);
struct wl_closure { struct wl_closure {
int count; int count;
const struct wl_message *message; const struct wl_message *message;

View file

@ -357,10 +357,12 @@ wl_client_connection_data(int fd, uint32_t mask, void *data)
struct wl_object *object; struct wl_object *object;
struct wl_closure *closure; struct wl_closure *closure;
const struct wl_message *message; const struct wl_message *message;
uint32_t p[2]; uint32_t p[WL_MAX_HEADER_U32];
uint32_t resource_flags; uint32_t resource_flags;
uint32_t object_id;
int opcode, size, since; int opcode, size, since;
int len; int len;
size_t header_size = wl_connection_header_size(connection);
if (mask & WL_EVENT_HANGUP) { if (mask & WL_EVENT_HANGUP) {
wl_client_destroy(client); wl_client_destroy(client);
@ -394,10 +396,9 @@ wl_client_connection_data(int fd, uint32_t mask, void *data)
} }
} }
while (len >= 0 && (size_t) len >= sizeof p) { while (len >= 0 && (size_t) len >= header_size) {
wl_connection_copy(connection, p, sizeof p); wl_connection_copy(connection, p, header_size);
opcode = p[1] & 0xffff; wl_connection_parse_header(connection, p, &object_id, &size, &opcode);
size = p[1] >> 16;
/* /*
* If the message is larger than the maximum size of the * If the message is larger than the maximum size of the
@ -424,12 +425,12 @@ wl_client_connection_data(int fd, uint32_t mask, void *data)
if (len < size) if (len < size)
break; break;
resource = wl_map_lookup(&client->objects, p[0]); resource = wl_map_lookup(&client->objects, object_id);
resource_flags = wl_map_lookup_flags(&client->objects, p[0]); resource_flags = wl_map_lookup_flags(&client->objects, object_id);
if (resource == NULL) { if (resource == NULL) {
wl_resource_post_error(client->display_resource, wl_resource_post_error(client->display_resource,
WL_DISPLAY_ERROR_INVALID_OBJECT, WL_DISPLAY_ERROR_INVALID_OBJECT,
"invalid object %u", p[0]); "invalid object %u", object_id);
break; break;
} }