@@ -334,6 +334,48 @@ ubsan_instrument_vla (location_t loc, tree size)
return t;
}
+/* Instrument assignment of variably modified types. */
+
+tree
+ubsan_instrument_vm_assign (location_t loc, tree a, tree b)
+{
+ tree t, tt;
+
+ gcc_assert (TREE_CODE (a) == ARRAY_TYPE);
+ gcc_assert (TREE_CODE (b) == ARRAY_TYPE);
+
+ tree as = TYPE_MAX_VALUE (TYPE_DOMAIN (a));
+ tree bs = TYPE_MAX_VALUE (TYPE_DOMAIN (b));
+
+ as = fold_build2 (PLUS_EXPR, sizetype, as, size_one_node);
+ bs = fold_build2 (PLUS_EXPR, sizetype, bs, size_one_node);
+
+ t = build2 (NE_EXPR, boolean_type_node, as, bs);
+ if (flag_sanitize_trap & SANITIZE_VLA)
+ tt = build_call_expr_loc (loc, builtin_decl_explicit (BUILT_IN_TRAP), 0);
+ else
+ {
+ tree data = ubsan_create_data ("__ubsan_vm_data", 1, &loc,
+ ubsan_type_descriptor (a, UBSAN_PRINT_ARRAY),
+ ubsan_type_descriptor (b, UBSAN_PRINT_ARRAY),
+ ubsan_type_descriptor (sizetype),
+ NULL_TREE, NULL_TREE);
+ data = build_fold_addr_expr_loc (loc, data);
+ enum built_in_function bcode
+ = (flag_sanitize_recover & SANITIZE_VLA)
+ ? BUILT_IN_UBSAN_HANDLE_VM_BOUNDS_MISMATCH
+ : BUILT_IN_UBSAN_HANDLE_VM_BOUNDS_MISMATCH_ABORT;
+ tt = builtin_decl_explicit (bcode);
+ tt = build_call_expr_loc (loc, tt, 3, data,
+ ubsan_encode_value (as),
+ ubsan_encode_value (bs));
+ }
+ t = build3 (COND_EXPR, void_type_node, t, tt, void_node);
+
+ return t;
+}
+
+
/* Instrument missing return in C++ functions returning non-void. */
tree
@@ -26,6 +26,7 @@ extern tree ubsan_instrument_shift (location_t, enum tree_code, tree, tree);
extern tree ubsan_instrument_vla (location_t, tree);
extern tree ubsan_instrument_return (location_t);
extern tree ubsan_instrument_bounds (location_t, tree, tree *, bool);
+extern tree ubsan_instrument_vm_assign (location_t, tree, tree);
extern bool ubsan_array_ref_instrumented_p (const_tree);
extern void ubsan_maybe_instrument_array_ref (tree *, bool);
extern void ubsan_maybe_instrument_reference (tree *);
@@ -93,6 +93,7 @@ static tree qualify_type (tree, tree);
struct comptypes_data;
static int tagged_types_compatible_p (const_tree, const_tree, struct comptypes_data *);
static int comp_target_types (location_t, tree, tree);
+static int comp_target_types_instr (location_t, tree, tree, tree *);
static int function_types_compatible_p (const_tree, const_tree, struct comptypes_data *);
static int type_lists_compatible_p (const_tree, const_tree, struct comptypes_data *);
static tree lookup_field (tree, tree);
@@ -1053,6 +1054,9 @@ struct comptypes_data {
bool enum_and_int_p;
bool different_types_p;
+
+ location_t loc;
+ tree instrument_expr;
};
/* Return 1 if TYPE1 and TYPE2 are compatible types for assignment
@@ -1075,20 +1079,35 @@ comptypes (tree type1, tree type2)
/* Like comptypes, but if it returns non-zero because enum and int are
compatible, it sets *ENUM_AND_INT_P to true. */
-int
-comptypes_check_enum_int (tree type1, tree type2, bool *enum_and_int_p)
+static int
+comptypes_check_enum_int_instr (tree type1, tree type2, bool *enum_and_int_p, location_t loc, tree *instrument_expr)
{
int val;
struct comptypes_data data = { };
+
+ data.loc = loc;
+
+ if (NULL != instrument_expr)
+ data.instrument_expr = void_node;
+
val = comptypes_internal (type1, type2, &data);
*enum_and_int_p = data.enum_and_int_p;
+ if (NULL != instrument_expr)
+ *instrument_expr = data.instrument_expr;
+
free_all_tagged_seen (data.seen_base);
return val;
}
+int
+comptypes_check_enum_int (tree type1, tree type2, bool *enum_and_int_p)
+{
+ return comptypes_check_enum_int_instr (type1, type2, enum_and_int_p, UNKNOWN_LOCATION, NULL);
+}
+
/* Like comptypes, but if it returns nonzero for different types, it
sets *DIFFERENT_TYPES_P to true. */
@@ -1257,7 +1276,18 @@ comptypes_internal (const_tree type1, const_tree type2,
if (d1_variable != d2_variable)
data->different_types_p = true;
if (d1_variable || d2_variable)
- break;
+ {
+ if (NULL != data->instrument_expr)
+ {
+ tree instrument_expr2 = ubsan_instrument_vm_assign (data->loc,
+ TYPE_MAIN_VARIANT (t2),
+ TYPE_MAIN_VARIANT (t1));
+ /* chain into series of COMPOUND_EXPR */
+ data->instrument_expr = fold_build2 (COMPOUND_EXPR, void_type_node,
+ instrument_expr2, data->instrument_expr);
+ }
+ break;
+ }
if (d1_zero && d2_zero)
break;
if (d1_zero || d2_zero
@@ -1304,7 +1334,7 @@ comptypes_internal (const_tree type1, const_tree type2,
subset of the other. */
static int
-comp_target_types (location_t location, tree ttl, tree ttr)
+comp_target_types_instr (location_t location, tree ttl, tree ttr, tree *instrument_expr)
{
int val;
int val_ped;
@@ -1338,8 +1368,7 @@ comp_target_types (location_t location, tree ttl, tree ttr)
? c_build_qualified_type (TYPE_MAIN_VARIANT (mvr), TYPE_QUAL_ATOMIC)
: TYPE_MAIN_VARIANT (mvr));
- enum_and_int_p = false;
- val = comptypes_check_enum_int (mvl, mvr, &enum_and_int_p);
+ val = comptypes_check_enum_int_instr (mvl, mvr, &enum_and_int_p, location, instrument_expr);
if (val == 1 && val_ped != 1)
pedwarn_c11 (location, OPT_Wpedantic, "invalid use of pointers to arrays with different qualifiers "
@@ -1354,6 +1383,13 @@ comp_target_types (location_t location, tree ttl, tree ttr)
return val;
}
+
+static int
+comp_target_types (location_t location, tree ttl, tree ttr)
+{
+ return comp_target_types_instr (location, ttl, ttr, NULL);
+}
+
/* Subroutines of `comptypes'. */
@@ -1404,7 +1440,7 @@ free_all_tagged_seen (const struct tagged_seen_cache *cache)
static int
tagged_types_compatible_p (const_tree t1, const_tree t2,
- struct comptypes_data* data)
+ struct comptypes_data* data)
{
tree s1, s2;
bool needs_warning = false;
@@ -7080,6 +7116,7 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type,
if (coder == POINTER_TYPE && reject_gcc_builtin (rhs))
return error_mark_node;
+
/* A non-reference type can convert to a reference. This handles
va_start, va_copy and possibly port built-ins. */
if (codel == REFERENCE_TYPE && coder != REFERENCE_TYPE)
@@ -7284,6 +7321,7 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type,
int target_cmp = 0; /* Cache comp_target_types () result. */
addr_space_t asl;
addr_space_t asr;
+ tree instrument_expr = NULL;
if (TREE_CODE (mvl) != ARRAY_TYPE)
mvl = (TYPE_ATOMIC (mvl)
@@ -7478,12 +7516,17 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type,
}
}
+ bool instrument_p = sanitize_flags_p (SANITIZE_VLA)
+ && (ic_init_const != errtype)
+ && (ic_argpass != errtype);
+
/* Any non-function converts to a [const][volatile] void *
and vice versa; otherwise, targets must be the same.
Meanwhile, the lhs target must have all the qualifiers of the rhs. */
if ((VOID_TYPE_P (ttl) && !TYPE_ATOMIC (ttl))
|| (VOID_TYPE_P (ttr) && !TYPE_ATOMIC (ttr))
- || (target_cmp = comp_target_types (location, type, rhstype))
+ || (target_cmp = comp_target_types_instr (location, type, rhstype,
+ instrument_p ? &instrument_expr : NULL))
|| is_opaque_pointer
|| ((c_common_unsigned_type (mvl)
== c_common_unsigned_type (mvr))
@@ -7684,6 +7727,15 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type,
struct or union. */
warn_for_address_or_pointer_of_packed_member (type, orig_rhs);
+ if (instrument_expr != NULL)
+ {
+ /* We have to make sure that the rhs is evaluated first,
+ because we may use size expressions in it to check bounds. */
+ rhs = save_expr (rhs);
+ instrument_expr = fold_build2 (COMPOUND_EXPR, void_type_node, rhs, instrument_expr);
+ rhs = fold_build2 (COMPOUND_EXPR, TREE_TYPE (rhs), instrument_expr, rhs);
+ }
+
return convert (type, rhs);
}
else if (codel == POINTER_TYPE && coder == ARRAY_TYPE)
@@ -506,6 +506,10 @@ DEF_SANITIZER_BUILTIN(BUILT_IN_UBSAN_HANDLE_MISSING_RETURN,
"__ubsan_handle_missing_return",
BT_FN_VOID_PTR,
ATTR_NORETURN_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN(BUILT_IN_UBSAN_HANDLE_VM_BOUNDS_MISMATCH,
+ "__ubsan_handle_vm_bounds_mismatch",
+ BT_FN_VOID_PTR_PTR_PTR,
+ ATTR_COLD_NOTHROW_LEAF_LIST)
DEF_SANITIZER_BUILTIN(BUILT_IN_UBSAN_HANDLE_VLA_BOUND_NOT_POSITIVE,
"__ubsan_handle_vla_bound_not_positive",
BT_FN_VOID_PTR_PTR,
@@ -542,6 +546,10 @@ DEF_SANITIZER_BUILTIN(BUILT_IN_UBSAN_HANDLE_DIVREM_OVERFLOW_ABORT,
"__ubsan_handle_divrem_overflow_abort",
BT_FN_VOID_PTR_PTR_PTR,
ATTR_COLD_NORETURN_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN(BUILT_IN_UBSAN_HANDLE_VM_BOUNDS_MISMATCH_ABORT,
+ "__ubsan_handle_vm_bounds_mismatch_about",
+ BT_FN_VOID_PTR_PTR_PTR,
+ ATTR_COLD_NORETURN_NOTHROW_LEAF_LIST)
DEF_SANITIZER_BUILTIN(BUILT_IN_UBSAN_HANDLE_SHIFT_OUT_OF_BOUNDS_ABORT,
"__ubsan_handle_shift_out_of_bounds_abort",
BT_FN_VOID_PTR_PTR_PTR,
new file mode 100644
@@ -0,0 +1,149 @@
+/* { dg-do run } */
+/* { dg-options "-fsanitize=vla-bound" } */
+
+
+/* test return types */
+
+int m, n;
+
+static char (*z0(void))[5][5] { char (*p)[m][n] = 0; return p; }
+static char (*z1(void))[5][5] { char (*p)[5][n] = 0; return p; }
+static char (*z2(void))[5][5] { char (*p)[m][5] = 0; return p; }
+
+
+int main()
+{
+ m = 4, n = 3;
+
+ int u = 4;
+ int v = 3;
+
+ /* initialization */
+
+ char a[4];
+ char (*pa)[u] = &a;
+ char (*qa)[v] = &a;
+ /* { dg-output "bound 3 of type 'char \\\[\\\*\\\]' does not match bound 4 of type 'char \\\[4\\\]'\[^\n\r]*(\n|\r\n|\r)" } */
+
+ char b[u];
+ const char (*pb)[u] = &b;
+ char (*qb)[v] = &b;
+ /* { dg-output "\[^\n\r]*bound 3 of type 'char \\\[\\\*\\\]' does not match bound 4 of type 'char \\\[\\\*\\\]'\[^\n\r]*(\n|\r\n|\r)" } */
+
+ char c[4][3];
+ char (*pc0)[u][v] = &c;
+ char (*qc0)[v][u] = &c;
+ /* { dg-output "\[^\n\r]*bound 3 of type 'char \\\[\\\*\\\]\\\[\\\*\\\]' does not match bound 4 of type 'char \\\[4\\\]\\\[3\\\]'\[^\n\r]*(\n|\r\n|\r)" } */
+ /* { dg-output "\[^\n\r]*bound 4 of type 'char \\\[\\\*\\\]' does not match bound 3 of type 'char \\\[3\\\]'\[^\n\r]*(\n|\r\n|\r)" } */
+
+ char (*pc1)[u][3] = &c;
+ char (*qc1)[v][3] = &c;
+ /* { dg-output "\[^\n\r]*bound 3 of type 'char \\\[\\\*\\\]\\\[3\\\]' does not match bound 4 of type 'char \\\[4\\\]\\\[3\\\]'\[^\n\r]*(\n|\r\n|\r)" } */
+
+ char (*pc2)[4][v] = &c;
+ char (*qc2)[4][u] = &c;
+ /* { dg-output "\[^\n\r]*bound 4 of type 'char \\\[\\\*\\\]' does not match bound 3 of type 'char \\\[3\\\]'\[^\n\r]*(\n|\r\n|\r)" } */
+
+ char (*pc3)[][v] = &c;
+ char (*qc3)[][u] = &c;
+ /* { dg-output "\[^\n\r]*bound 4 of type 'char \\\[\\\*\\\]' does not match bound 3 of type 'char \\\[3\\\]'\[^\n\r]*(\n|\r\n|\r)" } */
+
+ char d[u][v];
+ char (*pd0)[4][3] = &d;
+ char (*qd0)[3][4] = &d;
+ /* { dg-output "\[^\n\r]*bound 3 of type 'char \\\[3\\\]\\\[4\\\]' does not match bound 4 of type 'char \\\[\\\*\\\]\\\[\\\*\\\]'\[^\n\r]*(\n|\r\n|\r)" } */
+ /* { dg-output "\[^\n\r]*bound 4 of type 'char \\\[4\\\]' does not match bound 3 of type 'char \\\[\\\*\\\]'\[^\n\r]*(\n|\r\n|\r)" } */
+
+ char (*pd1)[u][3] = &d;
+ char (*qd1)[v][4] = &d;
+ /* { dg-output "\[^\n\r]*bound 3 of type 'char \\\[\\\*\\\]\\\[4\\\]' does not match bound 4 of type 'char \\\[\\\*\\\]\\\[\\\*\\\]'\[^\n\r]*(\n|\r\n|\r)" } */
+ /* { dg-output "\[^\n\r]*bound 4 of type 'char \\\[4\\\]' does not match bound 3 of type 'char \\\[\\\*\\\]'\[^\n\r]*(\n|\r\n|\r)" } */
+
+ char (*pd2)[4][v] = &d;
+ char (*qd2)[3][u] = &d;
+ /* { dg-output "\[^\n\r]*bound 3 of type 'char \\\[3\\\]\\\[\\\*\\\]' does not match bound 4 of type 'char \\\[\\\*\\\]\\\[\\\*\\\]'\[^\n\r]*(\n|\r\n|\r)" } */
+ /* { dg-output "\[^\n\r]*bound 4 of type 'char \\\[\\\*\\\]' does not match bound 3 of type 'char \\\[\\\*\\\]'\[^\n\r]*(\n|\r\n|\r)" } */
+
+ char (*pd3)[u][v] = &d;
+ char (*qd3)[v][u] = &d;
+ /* { dg-output "\[^\n\r]*bound 3 of type 'char \\\[\\\*\\\]\\\[\\\*\\\]' does not match bound 4 of type 'char \\\[\\\*\\\]\\\[\\\*\\\]'\[^\n\r]*(\n|\r\n|\r)" } */
+ /* { dg-output "\[^\n\r]*bound 4 of type 'char \\\[\\\*\\\]' does not match bound 3 of type 'char \\\[\\\*\\\]'\[^\n\r]*(\n|\r\n|\r)" } */
+
+ char e[4][v];
+ char (*pe0)[4][3] = &e;
+ char (*qe0)[4][4] = &e;
+ /* { dg-output "\[^\n\r]*bound 4 of type 'char \\\[4\\\]' does not match bound 3 of type 'char \\\[\\\*\\\]'\[^\n\r]*(\n|\r\n|\r)" } */
+
+ char f[u][3];
+ char (*pf)[4][3] = &f;
+ char (*qf)[3][3] = &f;
+ /* { dg-output "\[^\n\r]*bound 3 of type 'char \\\[3\\\]\\\[3\\\]' does not match bound 4 of type 'char \\\[\\\*\\\]\\\[3\\\]'\[^\n\r]*(\n|\r\n|\r)" } */
+
+ char (*g[u])[v];
+ char (*(*pg)[u])[v] = &g;
+ char (*(*qg)[v])[u] = &g;
+ /* { dg-output "\[^\n\r]*bound 3 of type '\[^\]]*\\\[\\\*\\\]' does not match bound 4 of type '\[^\]]*\\\[\\\*\\\]'\[^\n\r]*(\n|\r\n|\r)" } */
+ /* { dg-output "\[^\n\r]*bound 4 of type 'char \\\[\\\*\\\]' does not match bound 3 of type 'char \\\[\\\*\\\]'\[^\n\r]*(\n|\r\n|\r)" } */
+
+ /* assignment */
+
+ pa = &a;
+ qa = &a;
+ /* { dg-output "\[^\n\r]*bound 3 of type 'char \\\[\\\*\\\]' does not match bound 4 of type 'char \\\[4\\\]'\[^\n\r]*(\n|\r\n|\r)" } */
+
+ pb = &b;
+ qb = &b;
+ /* { dg-output "\[^\n\r]*bound 3 of type 'char \\\[\\\*\\\]' does not match bound 4 of type 'char \\\[\\\*\\\]'\[^\n\r]*(\n|\r\n|\r)" } */
+
+ pc0 = &c;
+ qc0 = &c;
+ /* { dg-output "\[^\n\r]*bound 3 of type 'char \\\[\\\*\\\]\\\[\\\*\\\]' does not match bound 4 of type 'char \\\[4\\\]\\\[3\\\]'\[^\n\r]*(\n|\r\n|\r)" } */
+ /* { dg-output "\[^\n\r]*bound 4 of type 'char \\\[\\\*\\\]' does not match bound 3 of type 'char \\\[3\\\]'\[^\n\r]*(\n|\r\n|\r)" } */
+
+ pc1 = &c;
+ qc1 = &c;
+ /* { dg-output "\[^\n\r]*bound 3 of type 'char \\\[\\\*\\\]\\\[3\\\]' does not match bound 4 of type 'char \\\[4\\\]\\\[3\\\]'\[^\n\r]*(\n|\r\n|\r)" } */
+
+ pc2 = &c;
+ qc2 = &c;
+ /* { dg-output "\[^\n\r]*bound 4 of type 'char \\\[\\\*\\\]' does not match bound 3 of type 'char \\\[3\\\]'\[^\n\r]*(\n|\r\n|\r)" } */
+
+ pd0 = &d;
+ qd0 = &d;
+ /* { dg-output "\[^\n\r]*bound 3 of type 'char \\\[3\\\]\\\[4\\\]' does not match bound 4 of type 'char \\\[\\\*\\\]\\\[\\\*\\\]'\[^\n\r]*(\n|\r\n|\r)" } */
+ /* { dg-output "\[^\n\r]*bound 4 of type 'char \\\[4\\\]' does not match bound 3 of type 'char \\\[\\\*\\\]'\[^\n\r]*(\n|\r\n|\r)" } */
+
+ pd1 = &d;
+ qd1 = &d;
+ /* { dg-output "\[^\n\r]*bound 3 of type 'char \\\[\\\*\\\]\\\[4\\\]' does not match bound 4 of type 'char \\\[\\\*\\\]\\\[\\\*\\\]'\[^\n\r]*(\n|\r\n|\r)" } */
+ /* { dg-output "\[^\n\r]*bound 4 of type 'char \\\[4\\\]' does not match bound 3 of type 'char \\\[\\\*\\\]'\[^\n\r]*(\n|\r\n|\r)" } */
+
+ pd2 = &d;
+ qd2 = &d;
+ /* { dg-output "\[^\n\r]*bound 3 of type 'char \\\[3\\\]\\\[\\\*\\\]' does not match bound 4 of type 'char \\\[\\\*\\\]\\\[\\\*\\\]'\[^\n\r]*(\n|\r\n|\r)" } */
+ /* { dg-output "\[^\n\r]*bound 4 of type 'char \\\[\\\*\\\]' does not match bound 3 of type 'char \\\[\\\*\\\]'\[^\n\r]*(\n|\r\n|\r)" } */
+
+ pd3 = &d;
+ qd3 = &d;
+ /* { dg-output "\[^\n\r]*bound 3 of type 'char \\\[\\\*\\\]\\\[\\\*\\\]' does not match bound 4 of type 'char \\\[\\\*\\\]\\\[\\\*\\\]'\[^\n\r]*(\n|\r\n|\r)" } */
+ /* { dg-output "\[^\n\r]*bound 4 of type 'char \\\[\\\*\\\]' does not match bound 3 of type 'char \\\[\\\*\\\]'\[^\n\r]*(\n|\r\n|\r)" } */
+
+ pe0 = &e;
+ qe0 = &e;
+ /* { dg-output "\[^\n\r]*bound 4 of type 'char \\\[4\\\]' does not match bound 3 of type 'char \\\[\\\*\\\]'\[^\n\r]*(\n|\r\n|\r)" } */
+
+ pf = &f;
+ qf = &f;
+ /* { dg-output "\[^\n\r]*bound 3 of type 'char \\\[3\\\]\\\[3\\\]' does not match bound 4 of type 'char \\\[\\\*\\\]\\\[3\\\]'\[^\n\r]*(\n|\r\n|\r)" } */
+
+ /* return */
+ z0();
+ /* { dg-output "\[^\n\r]*bound 5 of type 'char \\\[5\\\]\\\[5\\\]' does not match bound 4 of type 'char \\\[\\\*\\\]\\\[\\\*\\\]'\[^\n\r]*(\n|\r\n|\r)" } */
+ /* { dg-output "\[^\n\r]*bound 5 of type 'char \\\[5\\\]' does not match bound 3 of type 'char \\\[\\\*\\\]'\[^\n\r]*(\n|\r\n|\r)" } */
+
+ z1();
+ /* { dg-output "\[^\n\r]*bound 5 of type 'char \\\[5\\\]' does not match bound 3 of type 'char \\\[\\\*\\\]'\[^\n\r]*(\n|\r\n|\r)" } */
+ z2();
+ /* { dg-output "\[^\n\r]*bound 5 of type 'char \\\[5\\\]\\\[5\\\]' does not match bound 4 of type 'char \\\[\\\*\\\]\\\[5\\\]'\[^\n\r]*(\n|\r\n|\r)" } */
+}
+
new file mode 100644
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "-fsanitize=vla-bound" } */
+
+
+
+const char* name = "hallo";
+
+
+void f(void)
+{
+ int x = 1;
+ int (*m)[x] = 0;
+ m = ({ long* d2; (int (*)[d2[0]])(0); });
+}
+
@@ -56,6 +56,7 @@ UBSAN_CHECK(OutOfBoundsIndex, "out-of-bounds-index", "bounds")
UBSAN_CHECK(UnreachableCall, "unreachable-call", "unreachable")
UBSAN_CHECK(MissingReturn, "missing-return", "return")
UBSAN_CHECK(NonPositiveVLAIndex, "non-positive-vla-index", "vla-bound")
+UBSAN_CHECK(VMBoundsMismatch, "vm-bounds-mismatch", "vm-bounds")
UBSAN_CHECK(FloatCastOverflow, "float-cast-overflow", "float-cast-overflow")
UBSAN_CHECK(InvalidBoolLoad, "invalid-bool-load", "bool")
UBSAN_CHECK(InvalidEnumLoad, "invalid-enum-load", "enum")
@@ -433,6 +433,33 @@ void __ubsan::__ubsan_handle_missing_return(UnreachableData *Data) {
Die();
}
+static void handleVMBoundsMismatch(VMBoundsMismatchData *Data, ValueHandle Bound1,
+ ValueHandle Bound2, ReportOptions Opts) {
+ SourceLocation Loc = Data->Loc.acquire();
+ ErrorType ET = ErrorType::NonPositiveVLAIndex;
+
+ if (ignoreReport(Loc, Opts, ET))
+ return;
+
+ ScopedReport R(Opts, Loc, ET);
+
+ Diag(Loc, DL_Error, ET, "bound %0 of type %1 does not match bound %2 of type %3")
+ << Value(Data->IndexType, Bound2) << Data->ToType
+ << Value(Data->IndexType, Bound1) << Data->FromType;
+}
+
+void __ubsan::__ubsan_handle_vm_bounds_mismatch(VMBoundsMismatchData *Data,
+ ValueHandle Bound1, ValueHandle Bound2) {
+ GET_REPORT_OPTIONS(false);
+ handleVMBoundsMismatch(Data, Bound1, Bound2, Opts);
+}
+void __ubsan::__ubsan_handle_vm_bounds_mismatch_abort(VMBoundsMismatchData *Data,
+ ValueHandle Bound1, ValueHandle Bound2) {
+ GET_REPORT_OPTIONS(true);
+ handleVMBoundsMismatch(Data, Bound1, Bound2, Opts);
+ Die();
+}
+
static void handleVLABoundNotPositive(VLABoundData *Data, ValueHandle Bound,
ReportOptions Opts) {
SourceLocation Loc = Data->Loc.acquire();
@@ -107,6 +107,17 @@ struct VLABoundData {
/// \brief Handle a VLA with a non-positive bound.
RECOVERABLE(vla_bound_not_positive, VLABoundData *Data, ValueHandle Bound)
+struct VMBoundsMismatchData {
+ SourceLocation Loc;
+ const TypeDescriptor &FromType;
+ const TypeDescriptor &ToType;
+ const TypeDescriptor &IndexType;
+};
+
+/// \brief Handle a VM types with run-time bounds mismatch
+RECOVERABLE(vm_bounds_mismatch, VMBoundsMismatchData *Data, ValueHandle Bound1, ValueHandle Bound2)
+
+
// Keeping this around for binary compatibility with (sanitized) programs
// compiled with older compilers.
struct FloatCastOverflowData {