draw: check for an integer overflow when computing stride
authorZack Rusin <zackr@vmware.com>
Tue, 25 Jun 2013 20:14:06 +0000 (16:14 -0400)
committerZack Rusin <zackr@vmware.com>
Fri, 28 Jun 2013 08:24:16 +0000 (04:24 -0400)
Our buffer overflow arithmetic was susceptible to integer
overflows which was the buffer overflow logic to break.
Lets use the llvm overflow intrinsics to check for integer
overflows while computing the stride/needed buffer size.

Signed-off-by: Zack Rusin <zackr@vmware.com>
src/gallium/auxiliary/draw/draw_llvm.c

index f27776a5cc539b6cea6f6fe7a901c3a922d39889..c1b4acd25a864d43bef7cd6b4abfc78729469449 100644 (file)
@@ -699,6 +699,13 @@ generate_fetch(struct gallivm_state *gallivm,
    LLVMValueRef temp_ptr =
       lp_build_alloca(gallivm,
                       lp_build_vec_type(gallivm, lp_float32_vec4_type()), "");
+   LLVMValueRef ofbit, oresult;
+   LLVMTypeRef oelems[2] = {
+      LLVMInt32TypeInContext(gallivm->context),
+      LLVMInt1TypeInContext(gallivm->context)
+   };
+   LLVMTypeRef otype = LLVMStructTypeInContext(gallivm->context,
+                                               oelems, 2, FALSE);
    struct lp_build_if_state if_ctx;
 
    if (velem->instance_divisor) {
@@ -708,23 +715,49 @@ generate_fetch(struct gallivm_state *gallivm,
                             "instance_divisor");
    }
 
-   stride = LLVMBuildMul(builder, vb_stride, index, "");
+   oresult = lp_build_intrinsic_binary(builder,
+                                       "llvm.umul.with.overflow.i32",
+                                       otype, vb_stride, index);
+   ofbit = LLVMBuildExtractValue(builder, oresult, 1, "");
+   stride = LLVMBuildExtractValue(builder, oresult, 0, "");
+
+   oresult = lp_build_intrinsic_binary(builder,
+                                       "llvm.uadd.with.overflow.i32",
+                                       otype, stride, vb_buffer_offset);
+   ofbit = LLVMBuildOr(
+      builder, ofbit,
+      LLVMBuildExtractValue(builder, oresult,  1, ""),
+      "");
+   stride = LLVMBuildExtractValue(builder, oresult, 0, "");
+
+   oresult = lp_build_intrinsic_binary(
+      builder,
+      "llvm.uadd.with.overflow.i32",
+      otype, stride,
+      lp_build_const_int32(gallivm, velem->src_offset));
+   ofbit = LLVMBuildOr(
+      builder, ofbit,
+      LLVMBuildExtractValue(builder, oresult, 1, ""),
+      "");
+   stride = LLVMBuildExtractValue(builder, oresult,  0, "");
 
-   stride = LLVMBuildAdd(builder, stride,
-                         vb_buffer_offset,
-                         "");
-   stride = LLVMBuildAdd(builder, stride,
-                         lp_build_const_int32(gallivm, velem->src_offset),
-                         "");
-   needed_buffer_size = LLVMBuildAdd(
-      builder, stride,
+
+   oresult = lp_build_intrinsic_binary(
+      builder,
+      "llvm.uadd.with.overflow.i32",
+      otype, stride,
       lp_build_const_int32(gallivm,
-                           util_format_get_blocksize(velem->src_format)),
+                           util_format_get_blocksize(velem->src_format)));
+   ofbit = LLVMBuildOr(
+      builder, ofbit,
+      LLVMBuildExtractValue(builder, oresult, 1, ""),
       "");
+   needed_buffer_size = LLVMBuildExtractValue(builder, oresult, 0, "");
 
    buffer_overflowed = LLVMBuildICmp(builder, LLVMIntUGT,
                                      needed_buffer_size, buffer_size,
                                      "buffer_overflowed");
+   buffer_overflowed = LLVMBuildOr(builder, buffer_overflowed, ofbit, "");
 #if 0
    lp_build_printf(gallivm, "vbuf index = %u, vb_stride is %u\n",
                    index, vb_stride);