[PATCH wayland v3 3/3] server: use the new wl_priv_signal for wl_resource

Giulio Camuffo giuliocamuffo at gmail.com
Tue Jan 24 14:34:30 UTC 2017


The old wl_signal is kept for backwards compatibility, as that is also
present in the deprecated public wl_resource struct, and that must be
kept working.
---
 src/wayland-server.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 46 insertions(+), 6 deletions(-)

diff --git a/src/wayland-server.c b/src/wayland-server.c
index 86fa025..49ce7b1 100644
--- a/src/wayland-server.c
+++ b/src/wayland-server.c
@@ -117,11 +117,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 {
@@ -597,6 +602,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)
 {
@@ -604,7 +634,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)
@@ -716,14 +750,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.
@@ -1490,7 +1529,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;
@@ -1858,7 +1898,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;
 }
-- 
2.11.0



More information about the wayland-devel mailing list