On Tue, Feb 09, 2016 at 04:03:48PM -0600, Derek Foreman wrote: > If a compositor is rendering in one thread while dispatching wayland > events in another, a wl_shm_pool_resize() could change the memory > mappings it's rendering from and cause a crash. > > Now we defer wl_shm_pool_resize() if the compositor has references on a > pool, and perform the actual resize when it drops those references. > > Signed-off-by: Derek Foreman <der...@osg.samsung.com>
Reviewed-by: Bryce Harrington <br...@osg.samsung.com> > --- > src/wayland-shm.c | 47 +++++++++++++++++++++++++++++++++++------------ > 1 file changed, 35 insertions(+), 12 deletions(-) > > diff --git a/src/wayland-shm.c b/src/wayland-shm.c > index 6fbf34b..6351259 100644 > --- a/src/wayland-shm.c > +++ b/src/wayland-shm.c > @@ -56,6 +56,7 @@ struct wl_shm_pool { > int external_refcount; > char *data; > int32_t size; > + int32_t new_size; > }; > > struct wl_shm_buffer { > @@ -74,12 +75,35 @@ struct wl_shm_sigbus_data { > }; > > static void > +shm_pool_finish_resize(struct wl_shm_pool *pool) > +{ > + void *data; > + > + if (pool->size == pool->new_size) > + return; > + > + data = mremap(pool->data, pool->size, pool->new_size, MREMAP_MAYMOVE); > + if (data == MAP_FAILED) { > + wl_resource_post_error(pool->resource, > + WL_SHM_ERROR_INVALID_FD, > + "failed mremap"); > + return; > + } > + > + pool->data = data; > + pool->size = pool->new_size; > +} > + > +static void > shm_pool_unref(struct wl_shm_pool *pool, bool external) > { > - if (external) > + if (external) { > pool->external_refcount--; > - else > + if (pool->external_refcount == 0) > + shm_pool_finish_resize(pool); > + } else { > pool->internal_refcount--; > + } > > if (pool->internal_refcount + pool->external_refcount) > return; > @@ -202,7 +226,6 @@ shm_pool_resize(struct wl_client *client, struct > wl_resource *resource, > int32_t size) > { > struct wl_shm_pool *pool = wl_resource_get_user_data(resource); > - void *data; > > if (size < pool->size) { > wl_resource_post_error(resource, > @@ -211,16 +234,15 @@ shm_pool_resize(struct wl_client *client, struct > wl_resource *resource, > return; > } > > - data = mremap(pool->data, pool->size, size, MREMAP_MAYMOVE); > - if (data == MAP_FAILED) { > - wl_resource_post_error(resource, > - WL_SHM_ERROR_INVALID_FD, > - "failed mremap"); > - return; > - } > + pool->new_size = size; > > - pool->data = data; > - pool->size = size; > + /* If the compositor has taken references on this pool it > + * may be caching pointers into it. In that case we > + * defer the resize (which may move the entire mapping) > + * until the compositor finishes dereferencing the pool. > + */ > + if (pool->external_refcount == 0) > + shm_pool_finish_resize(pool); > } > > struct wl_shm_pool_interface shm_pool_interface = { > @@ -251,6 +273,7 @@ shm_create_pool(struct wl_client *client, struct > wl_resource *resource, > pool->internal_refcount = 1; > pool->external_refcount = 0; > pool->size = size; > + pool->new_size = size; > pool->data = mmap(NULL, size, > PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); > if (pool->data == MAP_FAILED) { > -- > 2.7.0 > > _______________________________________________ > wayland-devel mailing list > wayland-devel@lists.freedesktop.org > https://lists.freedesktop.org/mailman/listinfo/wayland-devel _______________________________________________ wayland-devel mailing list wayland-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/wayland-devel