[PATCH weston v3 14/17] compositor: check viewport source rect validity

Pekka Paalanen ppaalanen at gmail.com
Tue Apr 26 12:51:06 UTC 2016


From: Pekka Paalanen <pekka.paalanen at collabora.co.uk>

wp_viewporter spec requires protocol errors when the viewport is outside
the buffer area.

The viewport is checked in wl_surface.commit handler as the error needs
to be delivered as a reply to the commit, not at state apply time later
(e.g. with synchronized sub-surfaces, or at render time).

Signed-off-by: Pekka Paalanen <pekka.paalanen at collabora.co.uk>
---
 src/compositor.c | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 75 insertions(+)

diff --git a/src/compositor.c b/src/compositor.c
index 1d605c7..4dfa7b7 100644
--- a/src/compositor.c
+++ b/src/compositor.c
@@ -2804,6 +2804,71 @@ weston_surface_build_buffer_matrix(const struct weston_surface *surface,
 	weston_matrix_scale(matrix, vp->buffer.scale, vp->buffer.scale, 1);
 }
 
+/**
+ * Compute a + b > c while being safe to overflows.
+ */
+static bool
+fixed_sum_gt(wl_fixed_t a, wl_fixed_t b, wl_fixed_t c)
+{
+	return (int64_t)a + (int64_t)b > (int64_t)c;
+}
+
+static bool
+weston_surface_is_pending_viewport_source_valid(
+	const struct weston_surface *surface)
+{
+	const struct weston_surface_state *pend = &surface->pending;
+	const struct weston_buffer_viewport *vp = &pend->buffer_viewport;
+	int width_from_buffer = 0;
+	int height_from_buffer = 0;
+	wl_fixed_t w;
+	wl_fixed_t h;
+
+	/* If viewport source rect is not set, always ok. */
+	if (vp->buffer.src_width == wl_fixed_from_int(-1))
+		return true;
+
+	if (pend->newly_attached) {
+		if (pend->buffer) {
+			convert_size_by_transform_scale(&width_from_buffer,
+							&height_from_buffer,
+							pend->buffer->width,
+							pend->buffer->height,
+							vp->buffer.transform,
+							vp->buffer.scale);
+		} else {
+			/* No buffer, viewport is irrelevant. */
+			return true;
+		}
+	} else {
+		width_from_buffer = surface->width_from_buffer;
+		height_from_buffer = surface->height_from_buffer;
+	}
+
+	assert((width_from_buffer == 0) == (height_from_buffer == 0));
+	assert(width_from_buffer >= 0 && height_from_buffer >= 0);
+
+	/* No buffer, viewport is irrelevant. */
+	if (width_from_buffer == 0 || height_from_buffer == 0)
+		return true;
+
+	/* overflow checks for wl_fixed_from_int() */
+	if (width_from_buffer > wl_fixed_to_int(INT32_MAX))
+		return false;
+	if (height_from_buffer > wl_fixed_to_int(INT32_MAX))
+		return false;
+
+	w = wl_fixed_from_int(width_from_buffer);
+	h = wl_fixed_from_int(height_from_buffer);
+
+	if (fixed_sum_gt(vp->buffer.src_x, vp->buffer.src_width, w))
+		return false;
+	if (fixed_sum_gt(vp->buffer.src_y, vp->buffer.src_height, h))
+		return false;
+
+	return true;
+}
+
 /* Translate pending damage in buffer co-ordinates to surface
  * co-ordinates and union it with a pixman_region32_t.
  * This should only be called after the buffer is attached.
@@ -2943,6 +3008,16 @@ surface_commit(struct wl_client *client, struct wl_resource *resource)
 	struct weston_surface *surface = wl_resource_get_user_data(resource);
 	struct weston_subsurface *sub = weston_surface_to_subsurface(surface);
 
+	if (!weston_surface_is_pending_viewport_source_valid(surface)) {
+		assert(surface->viewport_resource);
+
+		wl_resource_post_error(surface->viewport_resource,
+			WP_VIEWPORT_ERROR_OUT_OF_BUFFER,
+			"wl_surface@%d has viewport source outside buffer",
+			wl_resource_get_id(resource));
+		return;
+	}
+
 	if (sub) {
 		weston_subsurface_commit(sub);
 		return;
-- 
2.7.3



More information about the wayland-devel mailing list