[Mesa-dev] [PATCH] draw: don't crash on vertex buffer overflow

Zack Rusin zackr at vmware.com
Wed May 8 20:50:56 PDT 2013


We would crash when stride was bigger than the size of the buffer.
The correct behavior is to just fetch zero's in this case.
Unfortunatly gallium allows user_buffers in vertex_buffers and we
can't figure out the sizes of those, so we need to null check
the buffer to see if we can at all perform the check.

Signed-off-by: Zack Rusin <zackr at vmware.com>
---
 src/gallium/auxiliary/draw/draw_llvm.c |  145 +++++++++++++++++++++++++++++---
 src/gallium/auxiliary/draw/draw_llvm.h |   16 ++++
 src/gallium/auxiliary/draw/draw_pt.c   |    3 +-
 3 files changed, 151 insertions(+), 13 deletions(-)

diff --git a/src/gallium/auxiliary/draw/draw_llvm.c b/src/gallium/auxiliary/draw/draw_llvm.c
index d2821a1..194854d 100644
--- a/src/gallium/auxiliary/draw/draw_llvm.c
+++ b/src/gallium/auxiliary/draw/draw_llvm.c
@@ -78,6 +78,58 @@ draw_gs_llvm_iface(const struct lp_build_tgsi_gs_iface *iface)
 }
 
 /**
+ * Create LLVM type for pipe_resource, which is inside the
+ * pipe_vertex_buffer
+ */
+static LLVMTypeRef
+create_jit_resource_type(struct gallivm_state *gallivm,
+                         const char *struct_name)
+{
+   LLVMTargetDataRef target = gallivm->target;
+   LLVMTypeRef resource_type;
+   LLVMTypeRef elem_types[DRAW_JIT_RESOURCE_NUM_FIELDS];
+   LLVMTypeRef int32_type = LLVMInt32TypeInContext(gallivm->context);
+
+   elem_types[DRAW_JIT_RESOURCE_REFERENCE] = int32_type;
+   elem_types[DRAW_JIT_RESOURCE_SCREEN] =
+      LLVMPointerType(LLVMInt8TypeInContext(gallivm->context), 0);
+   
+   elem_types[DRAW_JIT_RESOURCE_TARGET] = int32_type;
+   elem_types[DRAW_JIT_RESOURCE_FORMAT] = int32_type;
+   elem_types[DRAW_JIT_RESOURCE_WIDTH0] = int32_type;
+
+   resource_type = LLVMStructTypeInContext(gallivm->context, elem_types,
+                                           Elements(elem_types), 0);
+
+#if HAVE_LLVM < 0x0300
+   LLVMAddTypeName(gallivm->module, struct_name, resource_type);
+
+   /* Make sure the target's struct layout cache doesn't return
+    * stale/invalid data.
+    */
+   LLVMInvalidateStructLayout(gallivm->target, resource_type);
+#endif
+
+   LP_CHECK_MEMBER_OFFSET(struct pipe_resource, reference,
+                          target, resource_type,
+                          DRAW_JIT_RESOURCE_REFERENCE);
+   LP_CHECK_MEMBER_OFFSET(struct pipe_resource, screen,
+                          target, resource_type,
+                          DRAW_JIT_RESOURCE_SCREEN);
+   LP_CHECK_MEMBER_OFFSET(struct pipe_resource, target,
+                          target, resource_type,
+                          DRAW_JIT_RESOURCE_TARGET);
+   LP_CHECK_MEMBER_OFFSET(struct pipe_resource, format,
+                          target, resource_type,
+                          DRAW_JIT_RESOURCE_FORMAT);
+   LP_CHECK_MEMBER_OFFSET(struct pipe_resource, width0,
+                          target, resource_type,
+                          DRAW_JIT_RESOURCE_WIDTH0);
+
+   return resource_type;
+}
+
+/**
  * Create LLVM type for struct draw_jit_texture
  */
 static LLVMTypeRef
@@ -328,7 +380,9 @@ create_gs_jit_input_type(struct gallivm_state *gallivm)
  * Create LLVM type for struct pipe_vertex_buffer
  */
 static LLVMTypeRef
-create_jit_vertex_buffer_type(struct gallivm_state *gallivm, const char *struct_name)
+create_jit_vertex_buffer_type(struct gallivm_state *gallivm,
+                              LLVMTypeRef resource_type,
+                              const char *struct_name)
 {
    LLVMTargetDataRef target = gallivm->target;
    LLVMTypeRef elem_types[4];
@@ -336,8 +390,8 @@ create_jit_vertex_buffer_type(struct gallivm_state *gallivm, const char *struct_
 
    elem_types[0] =
    elem_types[1] = LLVMInt32TypeInContext(gallivm->context);
-   elem_types[2] =
-   elem_types[3] = LLVMPointerType(LLVMInt8TypeInContext(gallivm->context), 0); /* vs_constants */
+   elem_types[2] = LLVMPointerType(resource_type, 0);
+   elem_types[3] = LLVMPointerType(LLVMInt8TypeInContext(gallivm->context), 0);
 
    vb_type = LLVMStructTypeInContext(gallivm->context, elem_types,
                                      Elements(elem_types), 0);
@@ -351,6 +405,8 @@ create_jit_vertex_buffer_type(struct gallivm_state *gallivm, const char *struct_
                           target, vb_type, 0);
    LP_CHECK_MEMBER_OFFSET(struct pipe_vertex_buffer, buffer_offset,
                           target, vb_type, 1);
+   LP_CHECK_MEMBER_OFFSET(struct pipe_vertex_buffer, buffer,
+                          target, vb_type, 2);
 
    LP_CHECK_STRUCT_SIZE(struct pipe_vertex_buffer, target, vb_type);
 
@@ -422,7 +478,8 @@ static void
 create_jit_types(struct draw_llvm_variant *variant)
 {
    struct gallivm_state *gallivm = variant->gallivm;
-   LLVMTypeRef texture_type, sampler_type, context_type, buffer_type, vb_type;
+   LLVMTypeRef texture_type, sampler_type, context_type, buffer_type,
+      vb_type, resource_type;
 
    texture_type = create_jit_texture_type(gallivm, "texture");
    sampler_type = create_jit_sampler_type(gallivm, "sampler");
@@ -434,7 +491,10 @@ create_jit_types(struct draw_llvm_variant *variant)
    buffer_type = LLVMPointerType(LLVMIntTypeInContext(gallivm->context, 8), 0);
    variant->buffer_ptr_type = LLVMPointerType(buffer_type, 0);
 
-   vb_type = create_jit_vertex_buffer_type(gallivm, "pipe_vertex_buffer");
+   resource_type = create_jit_resource_type(gallivm, "pipe_resource");
+   
+   vb_type = create_jit_vertex_buffer_type(gallivm, resource_type,
+                                           "pipe_vertex_buffer");
    variant->vb_ptr_type = LLVMPointerType(vb_type, 0);
 }
 
@@ -631,6 +691,19 @@ generate_vs(struct draw_llvm_variant *variant,
    }
 }
 
+static LLVMValueRef
+is_pointer_valid(struct gallivm_state *gallivm,
+                 LLVMValueRef ptr)
+{
+   LLVMBuilderRef builder = gallivm->builder;
+   LLVMTypeRef any_ptr_type = LLVMPointerType(
+      LLVMInt8TypeInContext(gallivm->context), 0);
+   LLVMValueRef common_ptr = LLVMBuildBitCast(builder, ptr,
+                                              any_ptr_type, "");
+   LLVMValueRef null_ptr = LLVMConstNull(any_ptr_type);
+
+   return LLVMBuildICmp(builder, LLVMIntNE, common_ptr, null_ptr, "");
+}
 
 static void
 generate_fetch(struct gallivm_state *gallivm,
@@ -651,7 +724,16 @@ generate_fetch(struct gallivm_state *gallivm,
                                            &indices, 1, "");
    LLVMValueRef vb_stride = draw_jit_vbuffer_stride(gallivm, vbuf);
    LLVMValueRef vb_buffer_offset = draw_jit_vbuffer_offset(gallivm, vbuf);
+   LLVMValueRef resource = draw_jit_vbuffer_buffer(gallivm, vbuf);
    LLVMValueRef stride;
+   struct lp_build_if_state if_ctx;
+   LLVMValueRef buffer_overflowed, is_ptr_valid;
+   LLVMValueRef buffer_overflowed_ptr =
+      lp_build_alloca(gallivm,
+                      LLVMInt1TypeInContext(gallivm->context), "");
+   LLVMValueRef temp_ptr =
+      lp_build_alloca(gallivm,
+                      lp_build_vec_type(gallivm, lp_float32_vec4_type()), "");
 
    if (velem->instance_divisor) {
       /* array index = instance_id / instance_divisor */
@@ -671,14 +753,53 @@ generate_fetch(struct gallivm_state *gallivm,
                          lp_build_const_int32(gallivm, velem->src_offset),
                          "");
 
-/*   lp_build_printf(gallivm, "vbuf index = %d, stride is %d\n", indices, stride);*/
-   vbuffer_ptr = LLVMBuildGEP(builder, vbuffer_ptr, &stride, 1, "");
+   is_ptr_valid = is_pointer_valid(gallivm, resource);
+   lp_build_if(&if_ctx, gallivm, is_ptr_valid);
+   {
+      LLVMValueRef buffer_size = draw_jit_resource_width0(gallivm, resource);
+      buffer_overflowed = LLVMBuildICmp(builder, LLVMIntSGE,
+                                       stride, buffer_size,
+                                       "buffer_overflowed");
+      LLVMBuildStore(builder, buffer_overflowed, buffer_overflowed_ptr);
+   }
+   lp_build_else(&if_ctx);
+   {
+      LLVMBuildStore(
+         builder,
+         LLVMConstInt(LLVMInt1TypeInContext(gallivm->context), 0, 0),
+         buffer_overflowed_ptr);
+   }
+   lp_build_endif(&if_ctx);
+   
+
+   buffer_overflowed = LLVMBuildLoad(builder, buffer_overflowed_ptr,
+                                    "buffer_overflowed");
+   /*
+   lp_build_printf(gallivm, "vbuf index = %d, stride is %d\n", indices, stride);
+   lp_build_print_value(gallivm, "   buffer size = ", buffer_size);
+   lp_build_print_value(gallivm, "   buffer overflowed = ", buffer_overflowed);
+   */
+   lp_build_if(&if_ctx, gallivm, buffer_overflowed);
+   {
+      LLVMValueRef val =
+         lp_build_const_vec(gallivm, lp_float32_vec4_type(), 0);
+      LLVMBuildStore(builder, val, temp_ptr);
+   }
+   lp_build_else(&if_ctx);
+   {
+      LLVMValueRef val;
+      vbuffer_ptr = LLVMBuildGEP(builder, vbuffer_ptr, &stride, 1, "");
+
+      val = lp_build_fetch_rgba_aos(gallivm,
+                                    format_desc,
+                                    lp_float32_vec4_type(),
+                                    vbuffer_ptr,
+                                    zero, zero, zero);
+      LLVMBuildStore(builder, val, temp_ptr);
+   }
+   lp_build_endif(&if_ctx);
 
-   *res = lp_build_fetch_rgba_aos(gallivm,
-                                  format_desc,
-                                  lp_float32_vec4_type(),
-                                  vbuffer_ptr,
-                                  zero, zero, zero);
+   *res = LLVMBuildLoad(builder, temp_ptr, "aos");
 }
 
 static void
diff --git a/src/gallium/auxiliary/draw/draw_llvm.h b/src/gallium/auxiliary/draw/draw_llvm.h
index 5909fc1..17c9be74 100644
--- a/src/gallium/auxiliary/draw/draw_llvm.h
+++ b/src/gallium/auxiliary/draw/draw_llvm.h
@@ -173,6 +173,22 @@ enum {
 #define draw_jit_vbuffer_offset(_gallivm, _ptr)         \
    lp_build_struct_get(_gallivm, _ptr, 1, "buffer_offset")
 
+#define draw_jit_vbuffer_buffer(_gallivm, _ptr)         \
+   lp_build_struct_get(_gallivm, _ptr, 2, "buffer")
+
+
+enum {
+   DRAW_JIT_RESOURCE_REFERENCE = 0,
+   DRAW_JIT_RESOURCE_SCREEN,
+   DRAW_JIT_RESOURCE_TARGET,
+   DRAW_JIT_RESOURCE_FORMAT,
+   DRAW_JIT_RESOURCE_WIDTH0,
+   DRAW_JIT_RESOURCE_NUM_FIELDS  /* number of fields above */
+};
+
+#define draw_jit_resource_width0(_gallivm, _ptr)         \
+   lp_build_struct_get(_gallivm, _ptr, DRAW_JIT_RESOURCE_WIDTH0, "width0")
+
 
 /**
  * This structure is passed directly to the generated geometry shader.
diff --git a/src/gallium/auxiliary/draw/draw_pt.c b/src/gallium/auxiliary/draw/draw_pt.c
index 602d076..0c2bcae 100644
--- a/src/gallium/auxiliary/draw/draw_pt.c
+++ b/src/gallium/auxiliary/draw/draw_pt.c
@@ -524,10 +524,11 @@ draw_vbo(struct draw_context *draw,
       }
       debug_printf("Buffers:\n");
       for (i = 0; i < draw->pt.nr_vertex_buffers; i++) {
-         debug_printf("  %u: stride=%u offset=%u ptr=%p\n",
+         debug_printf("  %u: stride=%u offset=%u size=%d ptr=%p\n",
                       i,
                       draw->pt.vertex_buffer[i].stride,
                       draw->pt.vertex_buffer[i].buffer_offset,
+                      draw->pt.vertex_buffer[i].buffer ? draw->pt.vertex_buffer[i].buffer->width0 : 0,
                       draw->pt.user.vbuffer[i]);
       }
    }
-- 
1.7.10.4


More information about the mesa-dev mailing list