[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