diff options
-rw-r--r-- | src/wayland-server.c | 52 |
1 files changed, 46 insertions, 6 deletions
diff --git a/src/wayland-server.c b/src/wayland-server.c index 06f8ba2..ac634da 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -120,11 +120,16 @@ struct wl_resource { struct wl_object object; wl_resource_destroy_func_t destroy; struct wl_list link; - struct wl_signal destroy_signal; + /* Unfortunately some users of libwayland (e.g. mesa) still use the + * deprecated wl_resource struct, even if creating it with the new + * wl_resource_create(). So we cannot change the layout of the struct + * unless after the data field. */ + struct wl_signal deprecated_destroy_signal; struct wl_client *client; void *data; int version; wl_dispatcher_func_t dispatcher; + struct wl_priv_signal destroy_signal; }; struct wl_protocol_logger { @@ -600,6 +605,31 @@ wl_resource_post_no_memory(struct wl_resource *resource) WL_DISPLAY_ERROR_NO_MEMORY, "no memory"); } +/** Detect if a wl_resource uses the deprecated public definition. + * + * Before Wayland 1.2.0, the definition of struct wl_resource was public. + * It was made opaque just before 1.2.0, and later new fields were added. + * The new fields cannot be accessed if a program is using the deprecated + * defition, as there would not be memory allocated for them. + * + * The creation pattern for the deprecated definition was wl_resource_init() + * followed by wl_client_add_resource(). wl_resource_init() was an inline + * function and no longer exists, but binaries might still carry it. + * wl_client_add_resource() still exists for ABI compatiblity. + */ +static bool +resource_is_deprecated(struct wl_resource *resource) +{ + struct wl_map *map = &resource->client->objects; + int id = resource->object.id; + + /* wl_client_add_resource() marks deprecated resources with the flag. */ + if (wl_map_lookup_flags(map, id) & WL_MAP_ENTRY_LEGACY) + return true; + + return false; +} + static enum wl_iterator_result destroy_resource(void *element, void *data) { @@ -607,7 +637,11 @@ destroy_resource(void *element, void *data) struct wl_client *client = resource->client; uint32_t flags; - wl_signal_emit(&resource->destroy_signal, resource); + wl_signal_emit(&resource->deprecated_destroy_signal, resource); + /* Don't emit the new signal for deprecated resources, as that would + * access memory outside the bounds of the deprecated struct */ + if (!resource_is_deprecated(resource)) + wl_priv_signal_emit(&resource->destroy_signal, resource); flags = wl_map_lookup_flags(&client->objects, resource->object.id); if (resource->destroy) @@ -719,14 +753,19 @@ WL_EXPORT void wl_resource_add_destroy_listener(struct wl_resource *resource, struct wl_listener * listener) { - wl_signal_add(&resource->destroy_signal, listener); + if (resource_is_deprecated(resource)) + wl_signal_add(&resource->deprecated_destroy_signal, listener); + else + wl_priv_signal_add(&resource->destroy_signal, listener); } WL_EXPORT struct wl_listener * wl_resource_get_destroy_listener(struct wl_resource *resource, wl_notify_func_t notify) { - return wl_signal_get(&resource->destroy_signal, notify); + if (resource_is_deprecated(resource)) + return wl_signal_get(&resource->deprecated_destroy_signal, notify); + return wl_priv_signal_get(&resource->destroy_signal, notify); } /** Retrieve the interface name (class) of a resource object. @@ -1559,7 +1598,8 @@ wl_resource_create(struct wl_client *client, resource->object.interface = interface; resource->object.implementation = NULL; - wl_signal_init(&resource->destroy_signal); + wl_signal_init(&resource->deprecated_destroy_signal); + wl_priv_signal_init(&resource->destroy_signal); resource->destroy = NULL; resource->client = client; @@ -1927,7 +1967,7 @@ wl_client_add_resource(struct wl_client *client, } resource->client = client; - wl_signal_init(&resource->destroy_signal); + wl_signal_init(&resource->deprecated_destroy_signal); return resource->object.id; } |