mirror of
				https://gitlab.freedesktop.org/wayland/wayland.git
				synced 2025-11-03 09:01:42 -05:00 
			
		
		
		
	connection: Move object lookup out of wl_connection_demarshal()
On the client side where we queue up multiple events before dispatching, we need to look up the receiving proxy and argument proxies immediately before calling the handler. Between queueing up multiple events and eventually invoking the handler, previous handlers may have destroyed some of the proxies.
This commit is contained in:
		
							parent
							
								
									9fe75537ad
								
							
						
					
					
						commit
						5d2b32b1fd
					
				
					 4 changed files with 74 additions and 38 deletions
				
			
		| 
						 | 
				
			
			@ -706,12 +706,13 @@ wl_connection_demarshal(struct wl_connection *connection,
 | 
			
		|||
			break;
 | 
			
		||||
		case 'o':
 | 
			
		||||
			closure->types[i] = &ffi_type_pointer;
 | 
			
		||||
			object = (struct wl_object **) extra;
 | 
			
		||||
			extra += sizeof *object;
 | 
			
		||||
			closure->args[i] = object;
 | 
			
		||||
			id = (uint32_t **) extra;
 | 
			
		||||
			extra += sizeof *id;
 | 
			
		||||
			closure->args[i] = id;
 | 
			
		||||
			*id = p;
 | 
			
		||||
 | 
			
		||||
			if (*p == 0 && !arg.nullable) {
 | 
			
		||||
				printf("NULL new ID received on non-nullable "
 | 
			
		||||
			if (*id == 0 && !arg.nullable) {
 | 
			
		||||
				printf("NULL object received on non-nullable "
 | 
			
		||||
				       "type, message %s(%s)\n", message->name,
 | 
			
		||||
				       message->signature);
 | 
			
		||||
				*object = NULL;
 | 
			
		||||
| 
						 | 
				
			
			@ -719,29 +720,6 @@ wl_connection_demarshal(struct wl_connection *connection,
 | 
			
		|||
				goto err;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			*object = wl_map_lookup(objects, *p);
 | 
			
		||||
			if (*object == WL_ZOMBIE_OBJECT) {
 | 
			
		||||
				/* references object we've already
 | 
			
		||||
				 * destroyed client side */
 | 
			
		||||
				*object = NULL;
 | 
			
		||||
			} else if (*object == NULL && *p != 0) {
 | 
			
		||||
				printf("unknown object (%u), message %s(%s)\n",
 | 
			
		||||
				       *p, message->name, message->signature);
 | 
			
		||||
				*object = NULL;
 | 
			
		||||
				errno = EINVAL;
 | 
			
		||||
				goto err;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (*object != NULL && message->types[i-2] != NULL &&
 | 
			
		||||
			    (*object)->interface != message->types[i-2]) {
 | 
			
		||||
				printf("invalid object (%u), type (%s), "
 | 
			
		||||
					"message %s(%s)\n",
 | 
			
		||||
				       *p, (*object)->interface->name,
 | 
			
		||||
				       message->name, message->signature);
 | 
			
		||||
				errno = EINVAL;
 | 
			
		||||
				goto err;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			p++;
 | 
			
		||||
			break;
 | 
			
		||||
		case 'n':
 | 
			
		||||
| 
						 | 
				
			
			@ -828,6 +806,53 @@ wl_connection_demarshal(struct wl_connection *connection,
 | 
			
		|||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
wl_closure_lookup_objects(struct wl_closure *closure, struct wl_map *objects)
 | 
			
		||||
{
 | 
			
		||||
	struct wl_object **object;
 | 
			
		||||
	const struct wl_message *message;
 | 
			
		||||
	const char *signature;
 | 
			
		||||
	struct argument_details arg;
 | 
			
		||||
	int i, count;
 | 
			
		||||
	uint32_t id;
 | 
			
		||||
 | 
			
		||||
	message = closure->message;
 | 
			
		||||
	signature = message->signature;
 | 
			
		||||
	count = arg_count_for_signature(signature) + 2;
 | 
			
		||||
	for (i = 2; i < count; i++) {
 | 
			
		||||
		signature = get_next_argument(signature, &arg);
 | 
			
		||||
		switch (arg.type) {
 | 
			
		||||
		case 'o':
 | 
			
		||||
			id = **(uint32_t **) closure->args[i];
 | 
			
		||||
			object = closure->args[i];
 | 
			
		||||
			*object = wl_map_lookup(objects, id);
 | 
			
		||||
			if (*object == WL_ZOMBIE_OBJECT) {
 | 
			
		||||
				/* references object we've already
 | 
			
		||||
				 * destroyed client side */
 | 
			
		||||
				*object = NULL;
 | 
			
		||||
			} else if (*object == NULL && id != 0) {
 | 
			
		||||
				printf("unknown object (%u), message %s(%s)\n",
 | 
			
		||||
				       id, message->name, message->signature);
 | 
			
		||||
				*object = NULL;
 | 
			
		||||
				errno = EINVAL;
 | 
			
		||||
				return -1;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (*object != NULL && message->types[i-2] != NULL &&
 | 
			
		||||
			    (*object)->interface != message->types[i-2]) {
 | 
			
		||||
				printf("invalid object (%u), type (%s), "
 | 
			
		||||
				       "message %s(%s)\n",
 | 
			
		||||
				       id, (*object)->interface->name,
 | 
			
		||||
				       message->name, message->signature);
 | 
			
		||||
				errno = EINVAL;
 | 
			
		||||
				return -1;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
wl_closure_invoke(struct wl_closure *closure,
 | 
			
		||||
		  struct wl_object *target, void (*func)(void), void *data)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -499,9 +499,6 @@ queue_event(struct wl_display *display, int len)
 | 
			
		|||
	closure = wl_connection_demarshal(display->connection, size,
 | 
			
		||||
					  &display->objects, message);
 | 
			
		||||
 | 
			
		||||
	if (wl_debug)
 | 
			
		||||
		wl_closure_print(closure, &proxy->object, false);
 | 
			
		||||
 | 
			
		||||
	if (closure == NULL || create_proxies(proxy, closure) < 0) {
 | 
			
		||||
		fprintf(stderr, "Error demarshalling event\n");
 | 
			
		||||
		abort();
 | 
			
		||||
| 
						 | 
				
			
			@ -520,7 +517,7 @@ dispatch_event(struct wl_display *display, struct wl_event_queue *queue)
 | 
			
		|||
	struct wl_closure *closure;
 | 
			
		||||
	struct wl_proxy *proxy;
 | 
			
		||||
	uint32_t id;
 | 
			
		||||
	int opcode;
 | 
			
		||||
	int opcode, ret;
 | 
			
		||||
 | 
			
		||||
	closure = container_of(queue->event_list.next,
 | 
			
		||||
			       struct wl_closure, link);
 | 
			
		||||
| 
						 | 
				
			
			@ -528,14 +525,25 @@ dispatch_event(struct wl_display *display, struct wl_event_queue *queue)
 | 
			
		|||
	id = closure->buffer[0];
 | 
			
		||||
	opcode = closure->buffer[1] & 0xffff;
 | 
			
		||||
 | 
			
		||||
	/* Verify that the receiving object is still valid and look up
 | 
			
		||||
	 * proxies for any arguments.  We have to do this just before
 | 
			
		||||
	 * calling the handler, since preceeding events may have
 | 
			
		||||
	 * destroyed either the proxy or the proxy args since the
 | 
			
		||||
	 * event was queued. */
 | 
			
		||||
	proxy = wl_map_lookup(&display->objects, id);
 | 
			
		||||
	ret = wl_closure_lookup_objects(closure, &display->objects);
 | 
			
		||||
 | 
			
		||||
	pthread_mutex_unlock(&display->mutex);
 | 
			
		||||
 | 
			
		||||
	if (proxy != WL_ZOMBIE_OBJECT)
 | 
			
		||||
	if (proxy != WL_ZOMBIE_OBJECT && ret == 0) {
 | 
			
		||||
		if (wl_debug)
 | 
			
		||||
			wl_closure_print(closure, &proxy->object, false);
 | 
			
		||||
 | 
			
		||||
		wl_closure_invoke(closure, &proxy->object,
 | 
			
		||||
				  proxy->object.implementation[opcode],
 | 
			
		||||
				  proxy->user_data);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	wl_closure_destroy(closure);
 | 
			
		||||
 | 
			
		||||
	pthread_mutex_lock(&display->mutex);
 | 
			
		||||
| 
						 | 
				
			
			@ -546,7 +554,6 @@ WL_EXPORT int
 | 
			
		|||
wl_display_dispatch_queue(struct wl_display *display,
 | 
			
		||||
			  struct wl_event_queue *queue)
 | 
			
		||||
{
 | 
			
		||||
	struct wl_closure *closure;
 | 
			
		||||
	int len, size;
 | 
			
		||||
 | 
			
		||||
	pthread_mutex_lock(&display->mutex);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -99,6 +99,9 @@ wl_connection_demarshal(struct wl_connection *connection,
 | 
			
		|||
			struct wl_map *objects,
 | 
			
		||||
			const struct wl_message *message);
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
wl_closure_lookup_objects(struct wl_closure *closure, struct wl_map *objects);
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
wl_closure_invoke(struct wl_closure *closure,
 | 
			
		||||
		  struct wl_object *target, void (*func)(void), void *data);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -275,10 +275,8 @@ wl_client_connection_data(int fd, uint32_t mask, void *data)
 | 
			
		|||
						  &client->objects, message);
 | 
			
		||||
		len -= size;
 | 
			
		||||
 | 
			
		||||
		if (wl_debug)
 | 
			
		||||
			wl_closure_print(closure, object, false);
 | 
			
		||||
 | 
			
		||||
		if (closure == NULL && errno == EINVAL) {
 | 
			
		||||
		if ((closure == NULL && errno == EINVAL) ||
 | 
			
		||||
		    wl_closure_lookup_objects(closure, &client->objects) < 0) {
 | 
			
		||||
			wl_resource_post_error(client->display_resource,
 | 
			
		||||
					       WL_DISPLAY_ERROR_INVALID_METHOD,
 | 
			
		||||
					       "invalid arguments for %s@%u.%s",
 | 
			
		||||
| 
						 | 
				
			
			@ -291,6 +289,9 @@ wl_client_connection_data(int fd, uint32_t mask, void *data)
 | 
			
		|||
			break;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (wl_debug)
 | 
			
		||||
			wl_closure_print(closure, object, false);
 | 
			
		||||
 | 
			
		||||
		deref_new_objects(closure);
 | 
			
		||||
 | 
			
		||||
		wl_closure_invoke(closure, object,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue