On Tue, 19 Nov 2013 15:44:44 +0100 Lubomir Rintel <lkund...@v3.sk> wrote:
> 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 <lkund...@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 > > On Tue, 2013-11-19 at 14:23 +0200, Pekka Paalanen wrote: > > Otherwise looks good. > > > > We have the trade-off between less code (the first version of the > > patch), and not having a lingering ps->image referring to unusable > > memory (the second version of the patch). IMHO the latter is cleaner. > > I've found another issue; if a surface is removed, the destroy handler > will use-after-free the ps. Therefore I'm unhooking it once before ps > vanishes if it exists and only if it exists -- as the image data might > as well be a color fill without actual buffer attached. > > I found no better way of discovering whether it's appropriate to unhook > (buffer attached) or not (nothing attached or color-filled) that looking > at the notify callback pointer. It works well enough for me byt maybe > there's a cleaner solution? Right, looks like it should work. Another way would be to ensure, that buffer_destroy_listener.link is always removable. You can do that by initializing it with and always after remove calling wl_list_init() on it. That way wl_list_remove()'ing it is never illegal. Thanks, pq > src/pixman-renderer.c | 27 ++++++++++++++++++++++++++- > 1 file changed, 26 insertions(+), 1 deletion(-) > > diff --git a/src/pixman-renderer.c b/src/pixman-renderer.c > index b719829..c2c6ca9 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); > @@ -499,6 +516,13 @@ 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)); > + > + if (ps->buffer_destroy_listener.notify) > + wl_list_remove(&ps->buffer_destroy_listener.link); > + ps->buffer_destroy_listener.notify = > + buffer_state_handle_buffer_destroy; > + wl_signal_add(&buffer->destroy_signal, > + &ps->buffer_destroy_listener); > } > > static void > @@ -506,7 +530,8 @@ 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->surface->renderer_state = NULL; > _______________________________________________ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel