summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLubomir Rintel <lkundrak@v3.sk>2013-12-12 12:57:56 +0100
committerKristian Høgsberg <krh@bitplanet.net>2013-12-22 13:40:11 -0800
commitddc2b1ec326e7b1a178cf5aebf871985fb6b8aca (patch)
tree53230bae71dfbeec1e679ac5f6f6ea2a300f115a
parent24dff2b704a1cbf70b2785561934b83486c7f8fb (diff)
pixman: Destroy pixman images when underlying buffer is destroyed
While the pixman image might be attached, the underlying buffer might be already gone under certain circumstances. This is easily reproduced by attempting to resize gnome-terminal on a fbdev backend. $ WAYLAND_DEBUG=1 strace -emunmap weston --backend=fbdev-backend.so ... [1524826.942] wl_shm@7.create_pool(new id wl_shm_pool@23, fd 40, 1563540) [1524827.315] wl_shm_pool@23.create_buffer(new id wl_buffer@24, 0, 759, 515, 3036, 0) ... [1524829.488] wl_surface@14.attach(wl_buffer@24, 0, 0) [1524829.766] wl_surface@14.set_buffer_scale(1) [1524829.904] wl_surface@14.damage(0, 0, 759, 515) [1524830.248] wl_surface@14.frame(new id wl_callback@25) [1524830.450] wl_surface@14.commit() ... [1524846.706] wl_shm@7.create_pool(new id wl_shm_pool@26, fd 40, 1545000) [1524847.215] wl_shm_pool@26.create_buffer(new id wl_buffer@27, 0, 750, 515, 3000, 0) [1524847.735] wl_buffer@24.destroy() [1524847.953] -> wl_display@1.delete_id(24) [1524848.144] wl_shm_pool@23.destroy() munmap(0xb5b2e000, 1563540) = 0 [1524849.021] -> wl_display@1.delete_id(23) [1524849.425] wl_surface@14.attach(wl_buffer@27, 0, 0) [1524849.730] wl_surface@14.set_buffer_scale(1) [1524849.821] wl_surface@14.damage(0, 0, 750, 515) <No commit yet, so drawing is attempted from older buffer that used to be attached to the surface, which happens to come from a destroyed pool, resulting it an invalid read from address 0xb5b2e000> Signed-off-by: Lubomir Rintel <lkundrak@v3.sk>
-rw-r--r--src/pixman-renderer.c32
1 files changed, 31 insertions, 1 deletions
diff --git a/src/pixman-renderer.c b/src/pixman-renderer.c
index 7a695787..129affcd 100644
--- a/src/pixman-renderer.c
+++ b/src/pixman-renderer.c
@@ -42,6 +42,7 @@ struct pixman_surface_state {
pixman_image_t *image;
struct weston_buffer_reference buffer_ref;
+ struct wl_listener buffer_destroy_listener;
struct wl_listener surface_destroy_listener;
struct wl_listener renderer_destroy_listener;
};
@@ -468,6 +469,22 @@ pixman_renderer_flush_damage(struct weston_surface *surface)
}
static void
+buffer_state_handle_buffer_destroy(struct wl_listener *listener, void *data)
+{
+ struct pixman_surface_state *ps;
+
+ ps = container_of(listener, struct pixman_surface_state,
+ buffer_destroy_listener);
+
+ if (ps->image) {
+ pixman_image_unref(ps->image);
+ ps->image = NULL;
+ }
+
+ ps->buffer_destroy_listener.notify = NULL;
+}
+
+static void
pixman_renderer_attach(struct weston_surface *es, struct weston_buffer *buffer)
{
struct pixman_surface_state *ps = get_surface_state(es);
@@ -476,6 +493,11 @@ pixman_renderer_attach(struct weston_surface *es, struct weston_buffer *buffer)
weston_buffer_reference(&ps->buffer_ref, buffer);
+ if (ps->buffer_destroy_listener.notify) {
+ wl_list_remove(&ps->buffer_destroy_listener.link);
+ ps->buffer_destroy_listener.notify = NULL;
+ }
+
if (ps->image) {
pixman_image_unref(ps->image);
ps->image = NULL;
@@ -517,6 +539,11 @@ pixman_renderer_attach(struct weston_surface *es, struct weston_buffer *buffer)
buffer->width, buffer->height,
wl_shm_buffer_get_data(shm_buffer),
wl_shm_buffer_get_stride(shm_buffer));
+
+ ps->buffer_destroy_listener.notify =
+ buffer_state_handle_buffer_destroy;
+ wl_signal_add(&buffer->destroy_signal,
+ &ps->buffer_destroy_listener);
}
static void
@@ -524,7 +551,10 @@ pixman_renderer_surface_state_destroy(struct pixman_surface_state *ps)
{
wl_list_remove(&ps->surface_destroy_listener.link);
wl_list_remove(&ps->renderer_destroy_listener.link);
-
+ if (ps->buffer_destroy_listener.notify) {
+ wl_list_remove(&ps->buffer_destroy_listener.link);
+ ps->buffer_destroy_listener.notify = NULL;
+ }
ps->surface->renderer_state = NULL;