<div dir="ltr">Wouldn't it be better to do this in compositor.c and call renderer->attach(surface, NULL) when the buffer attached to a surface is destroyed ? Is there a case where a renderer wouldn't want this to be done ?</div>
<div class="gmail_extra"><br><br><div class="gmail_quote">On Thu, Nov 21, 2013 at 8:35 AM, Pekka Paalanen <span dir="ltr"><<a href="mailto:ppaalanen@gmail.com" target="_blank">ppaalanen@gmail.com</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div class="HOEnZb"><div class="h5">On Tue, 19 Nov 2013 15:44:44 +0100<br>
Lubomir Rintel <<a href="mailto:lkundrak@v3.sk">lkundrak@v3.sk</a>> wrote:<br>
<br>
> While the pixman image might be attached, the underlying buffer might be<br>
> already gone under certain circumstances. This is easily reproduced by<br>
> attempting to resize gnome-terminal on a fbdev backend.<br>
><br>
> $ WAYLAND_DEBUG=1 strace -emunmap weston --backend=fbdev-backend.so<br>
> ...<br>
> [1524826.942] wl_shm@7.create_pool(new id wl_shm_pool@23, fd 40, 1563540)<br>
> [1524827.315] wl_shm_pool@23.create_buffer(new id wl_buffer@24, 0, 759, 515, 3036, 0)<br>
> ...<br>
> [1524829.488] wl_surface@14.attach(wl_buffer@24, 0, 0)<br>
> [1524829.766] wl_surface@14.set_buffer_scale(1)<br>
> [1524829.904] wl_surface@14.damage(0, 0, 759, 515)<br>
> [1524830.248] wl_surface@14.frame(new id wl_callback@25)<br>
> [1524830.450] wl_surface@14.commit()<br>
> ...<br>
> [1524846.706] wl_shm@7.create_pool(new id wl_shm_pool@26, fd 40, 1545000)<br>
> [1524847.215] wl_shm_pool@26.create_buffer(new id wl_buffer@27, 0, 750, 515, 3000, 0)<br>
> [1524847.735] wl_buffer@24.destroy()<br>
> [1524847.953]  -> wl_display@1.delete_id(24)<br>
> [1524848.144] wl_shm_pool@23.destroy()<br>
> munmap(0xb5b2e000, 1563540)             = 0<br>
> [1524849.021]  -> wl_display@1.delete_id(23)<br>
> [1524849.425] wl_surface@14.attach(wl_buffer@27, 0, 0)<br>
> [1524849.730] wl_surface@14.set_buffer_scale(1)<br>
> [1524849.821] wl_surface@14.damage(0, 0, 750, 515)<br>
> <No commit yet, so drawing is attempted from older buffer that used to be<br>
>  attached to the surface, which happens to come from a destroyed pool,<br>
>  resulting it an invalid read from address 0xb5b2e000><br>
><br>
> Signed-off-by: Lubomir Rintel <<a href="mailto:lkundrak@v3.sk">lkundrak@v3.sk</a>><br>
> ---<br>
> Changes to v2:<br>
>   - Added listener instead of checking the buffer mapping,<br>
>     as suggested by Pekka Paalanen<br>
>   - Added more context to the commit message<br>
> Changes to v3:<br>
>   - Removed unnecessary buffer unreferences and signal handler unhook<br>
>     of itself after it was called, suggested by Pekka Paalanen<br>
>   - Unhook the signal if we destroy the surface or reattach the buffer<br>
>     to avoid circular attachment or call after the surface state is gone<br>
><br>
> On Tue, 2013-11-19 at 14:23 +0200, Pekka Paalanen wrote:<br>
> > Otherwise looks good.<br>
> ><br>
> > We have the trade-off between less code (the first version of the<br>
> > patch), and not having a lingering ps->image referring to unusable<br>
> > memory (the second version of the patch). IMHO the latter is cleaner.<br>
><br>
> I've found another issue; if a surface is removed, the destroy handler<br>
> will use-after-free the ps. Therefore I'm unhooking it once before ps<br>
> vanishes if it exists and only if it exists -- as the image data might<br>
> as well be a color fill without actual buffer attached.<br>
><br>
> I found no better way of discovering whether it's appropriate to unhook<br>
> (buffer attached) or not (nothing attached or color-filled) that looking<br>
> at the notify callback pointer. It works well enough for me byt maybe<br>
> there's a cleaner solution?<br>
<br>
</div></div>Right, looks like it should work. Another way would be to ensure, that<br>
buffer_destroy_listener.link is always removable. You can do that by<br>
initializing it with and always after remove calling wl_list_init() on<br>
it. That way wl_list_remove()'ing it is never illegal.<br>
<br>
<br>
Thanks,<br>
pq<br>
<div class="HOEnZb"><div class="h5"><br>
>  src/pixman-renderer.c | 27 ++++++++++++++++++++++++++-<br>
>  1 file changed, 26 insertions(+), 1 deletion(-)<br>
><br>
> diff --git a/src/pixman-renderer.c b/src/pixman-renderer.c<br>
> index b719829..c2c6ca9 100644<br>
> --- a/src/pixman-renderer.c<br>
> +++ b/src/pixman-renderer.c<br>
> @@ -42,6 +42,7 @@ struct pixman_surface_state {<br>
>       pixman_image_t *image;<br>
>       struct weston_buffer_reference buffer_ref;<br>
><br>
> +     struct wl_listener buffer_destroy_listener;<br>
>       struct wl_listener surface_destroy_listener;<br>
>       struct wl_listener renderer_destroy_listener;<br>
>  };<br>
> @@ -450,6 +451,22 @@ pixman_renderer_flush_damage(struct weston_surface *surface)<br>
>  }<br>
><br>
>  static void<br>
> +buffer_state_handle_buffer_destroy(struct wl_listener *listener, void *data)<br>
> +{<br>
> +     struct pixman_surface_state *ps;<br>
> +<br>
> +     ps = container_of(listener, struct pixman_surface_state,<br>
> +                       buffer_destroy_listener);<br>
> +<br>
> +     if (ps->image) {<br>
> +             pixman_image_unref(ps->image);<br>
> +             ps->image = NULL;<br>
> +     }<br>
> +<br>
> +     ps->buffer_destroy_listener.notify = NULL;<br>
> +}<br>
> +<br>
> +static void<br>
>  pixman_renderer_attach(struct weston_surface *es, struct weston_buffer *buffer)<br>
>  {<br>
>       struct pixman_surface_state *ps = get_surface_state(es);<br>
> @@ -499,6 +516,13 @@ pixman_renderer_attach(struct weston_surface *es, struct weston_buffer *buffer)<br>
>               buffer->width, buffer->height,<br>
>               wl_shm_buffer_get_data(shm_buffer),<br>
>               wl_shm_buffer_get_stride(shm_buffer));<br>
> +<br>
> +     if (ps->buffer_destroy_listener.notify)<br>
> +             wl_list_remove(&ps->buffer_destroy_listener.link);<br>
> +     ps->buffer_destroy_listener.notify =<br>
> +             buffer_state_handle_buffer_destroy;<br>
> +     wl_signal_add(&buffer->destroy_signal,<br>
> +                   &ps->buffer_destroy_listener);<br>
>  }<br>
><br>
>  static void<br>
> @@ -506,7 +530,8 @@ pixman_renderer_surface_state_destroy(struct pixman_surface_state *ps)<br>
>  {<br>
>       wl_list_remove(&ps->surface_destroy_listener.link);<br>
>       wl_list_remove(&ps->renderer_destroy_listener.link);<br>
> -<br>
> +     if (ps->buffer_destroy_listener.notify)<br>
> +             wl_list_remove(&ps->buffer_destroy_listener.link);<br>
><br>
>       ps->surface->renderer_state = NULL;<br>
><br>
<br>
</div></div><div class="HOEnZb"><div class="h5">_______________________________________________<br>
wayland-devel mailing list<br>
<a href="mailto:wayland-devel@lists.freedesktop.org">wayland-devel@lists.freedesktop.org</a><br>
<a href="http://lists.freedesktop.org/mailman/listinfo/wayland-devel" target="_blank">http://lists.freedesktop.org/mailman/listinfo/wayland-devel</a><br>
</div></div></blockquote></div><br><br clear="all"><div><br></div>-- <br>Arnaud Vrac
</div>