gallium/radeon: fix crash in r600_set_streamout_targets
authorNicolai Hähnle <nicolai.haehnle@amd.com>
Thu, 28 Apr 2016 20:11:42 +0000 (15:11 -0500)
committerNicolai Hähnle <nicolai.haehnle@amd.com>
Fri, 29 Apr 2016 16:55:06 +0000 (11:55 -0500)
Protect against dereferencing a gap in the targets array. This was triggered
by a test in the Khronos CTS.

Cc: "11.1 11.2" <mesa-stable@lists.freedesktop.org>
Reviewed-by: Marek Olšák <marek.olsak@amd.com>
src/gallium/drivers/r600/r600_state_common.c
src/gallium/drivers/radeon/r600_streamout.c

index 5317de0cbabc11da276113efb8fb23ad1dc68571..cac240e8fbaf31e82efbbac59f9a13e53561eac4 100644 (file)
@@ -2802,7 +2802,8 @@ static void r600_invalidate_buffer(struct pipe_context *ctx, struct pipe_resourc
        }
        /* Streamout buffers. */
        for (i = 0; i < rctx->b.streamout.num_targets; i++) {
-               if (rctx->b.streamout.targets[i]->b.buffer == &rbuffer->b.b) {
+               if (rctx->b.streamout.targets[i] &&
+                   rctx->b.streamout.targets[i]->b.buffer == &rbuffer->b.b) {
                        if (rctx->b.streamout.begin_emitted) {
                                r600_emit_streamout_end(&rctx->b);
                        }
index fc9ec4859f6a152abbd69e1081b2563e1eb9e256..a001700ea1935355f2fb19532b15a29be65d30f1 100644 (file)
@@ -116,7 +116,7 @@ void r600_set_streamout_targets(struct pipe_context *ctx,
 {
        struct r600_common_context *rctx = (struct r600_common_context *)ctx;
        unsigned i;
-        unsigned append_bitmask = 0;
+        unsigned enabled_mask = 0, append_bitmask = 0;
 
        /* Stop streamout. */
        if (rctx->streamout.num_targets && rctx->streamout.begin_emitted) {
@@ -126,18 +126,19 @@ void r600_set_streamout_targets(struct pipe_context *ctx,
        /* Set the new targets. */
        for (i = 0; i < num_targets; i++) {
                pipe_so_target_reference((struct pipe_stream_output_target**)&rctx->streamout.targets[i], targets[i]);
+               if (!targets[i])
+                       continue;
+
                r600_context_add_resource_size(ctx, targets[i]->buffer);
+               enabled_mask |= 1 << i;
                if (offsets[i] == ((unsigned)-1))
-                       append_bitmask |=  1 << i;
+                       append_bitmask |= 1 << i;
        }
        for (; i < rctx->streamout.num_targets; i++) {
                pipe_so_target_reference((struct pipe_stream_output_target**)&rctx->streamout.targets[i], NULL);
        }
 
-       rctx->streamout.enabled_mask = (num_targets >= 1 && targets[0] ? 1 : 0) |
-                                      (num_targets >= 2 && targets[1] ? 2 : 0) |
-                                      (num_targets >= 3 && targets[2] ? 4 : 0) |
-                                      (num_targets >= 4 && targets[3] ? 8 : 0);
+       rctx->streamout.enabled_mask = enabled_mask;
 
        rctx->streamout.num_targets = num_targets;
        rctx->streamout.append_bitmask = append_bitmask;