etnaviv: keep references to pending resources
authorLucas Stach <l.stach@pengutronix.de>
Fri, 9 Aug 2019 13:34:31 +0000 (15:34 +0200)
committerLucas Stach <dev@lynxeye.de>
Fri, 18 Oct 2019 17:03:25 +0000 (17:03 +0000)
As long as a resource is pending in any context we must not destroy
it, otherwise we'll hit a classical use-after-free with fireworks.
To avoid this take a reference when the resource is first added to
the pending set and put the reference when no longer pending.

Signed-off-by: Lucas Stach <l.stach@pengutronix.de>
Reviewed-by: Jonathan Marek <jonathan@marek.ca>
src/gallium/drivers/etnaviv/etnaviv_context.c
src/gallium/drivers/etnaviv/etnaviv_resource.c

index 219d1de45f09ad7cfa75c5fca3d4c69d996948e2..d2519f11a5a2ff8e26fab20808cb003877c09f42 100644 (file)
@@ -425,10 +425,13 @@ etna_cmd_stream_reset_notify(struct etna_cmd_stream *stream, void *priv)
    mtx_lock(&screen->lock);
    set_foreach(ctx->used_resources, entry) {
       struct etna_resource *rsc = (struct etna_resource *)entry->key;
+      struct pipe_resource *referenced = &rsc->base;
 
       rsc->status = 0;
 
       _mesa_set_remove_key(rsc->pending_ctx, ctx);
+
+      pipe_resource_reference(&referenced, NULL);
    }
    _mesa_set_clear(ctx->used_resources, NULL);
    mtx_unlock(&screen->lock);
index 3a58808d743fc8cac04afee33024ff5b102c9a0a..4ccf887f60004410051060adba166fafe1212d13 100644 (file)
@@ -464,17 +464,9 @@ etna_resource_changed(struct pipe_screen *pscreen, struct pipe_resource *prsc)
 static void
 etna_resource_destroy(struct pipe_screen *pscreen, struct pipe_resource *prsc)
 {
-   struct etna_screen *screen = etna_screen(pscreen);
    struct etna_resource *rsc = etna_resource(prsc);
 
-   mtx_lock(&screen->lock);
-   set_foreach(rsc->pending_ctx, entry) {
-      struct etna_context *ctx = (struct etna_context *)entry->key;
-
-      _mesa_set_remove_key(rsc->pending_ctx, ctx);
-   }
-   _mesa_set_destroy(rsc->pending_ctx, NULL);
-   mtx_unlock(&screen->lock);
+   assert(!_mesa_set_next_entry(rsc->pending_ctx, NULL));
 
    if (rsc->bo)
       etna_bo_del(rsc->bo);
@@ -618,6 +610,7 @@ etna_resource_used(struct etna_context *ctx, struct pipe_resource *prsc,
                    enum etna_resource_status status)
 {
    struct etna_screen *screen = ctx->screen;
+   struct pipe_resource *referenced = NULL;
    struct etna_resource *rsc;
 
    if (!prsc)
@@ -654,8 +647,11 @@ etna_resource_used(struct etna_context *ctx, struct pipe_resource *prsc,
 
    rsc->status |= status;
 
-   _mesa_set_add(ctx->used_resources, rsc);
-   _mesa_set_add(rsc->pending_ctx, ctx);
+   if (!_mesa_set_search(rsc->pending_ctx, ctx)) {
+      pipe_resource_reference(&referenced, prsc);
+      _mesa_set_add(ctx->used_resources, rsc);
+      _mesa_set_add(rsc->pending_ctx, ctx);
+   }
 
    mtx_unlock(&screen->lock);
 }