[PATCH weston v5] pixman: Destroy pixman images when underlying buffer is destroyed
Lubomir Rintel
lkundrak at v3.sk
Thu Dec 12 03:57:56 PST 2013
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 at 7.create_pool(new id wl_shm_pool at 23, fd 40, 1563540)
[1524827.315] wl_shm_pool at 23.create_buffer(new id wl_buffer at 24, 0, 759, 515, 3036, 0)
...
[1524829.488] wl_surface at 14.attach(wl_buffer at 24, 0, 0)
[1524829.766] wl_surface at 14.set_buffer_scale(1)
[1524829.904] wl_surface at 14.damage(0, 0, 759, 515)
[1524830.248] wl_surface at 14.frame(new id wl_callback at 25)
[1524830.450] wl_surface at 14.commit()
...
[1524846.706] wl_shm at 7.create_pool(new id wl_shm_pool at 26, fd 40, 1545000)
[1524847.215] wl_shm_pool at 26.create_buffer(new id wl_buffer at 27, 0, 750, 515, 3000, 0)
[1524847.735] wl_buffer at 24.destroy()
[1524847.953] -> wl_display at 1.delete_id(24)
[1524848.144] wl_shm_pool at 23.destroy()
munmap(0xb5b2e000, 1563540) = 0
[1524849.021] -> wl_display at 1.delete_id(23)
[1524849.425] wl_surface at 14.attach(wl_buffer at 27, 0, 0)
[1524849.730] wl_surface at 14.set_buffer_scale(1)
[1524849.821] wl_surface at 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 at v3.sk>
---
Changes to v2:
- Added listener instead of checking the buffer mapping,
as suggested by Pekka Paalanen
- Added more context to the commit message
Changes to v3:
- Removed unnecessary buffer unreferences and signal handler unhook
of itself after it was called, suggested by Pekka Paalanen
- Unhook the signal if we destroy the surface or reattach the buffer
to avoid circular attachment or call after the surface state is gone
Changes to v4:
- Unhook the listener early when replacing surface's buffer
Changes to v5:
- Unhook the listener properly
src/pixman-renderer.c | 32 +++++++++++++++++++++++++++++++-
1 file changed, 31 insertions(+), 1 deletion(-)
diff --git a/src/pixman-renderer.c b/src/pixman-renderer.c
index e854e2a..69b29c6 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;
};
@@ -450,6 +451,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);
@@ -458,6 +475,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;
@@ -499,6 +521,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
@@ -506,7 +533,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;
--
1.8.4.2
More information about the wayland-devel
mailing list