aboutsummaryrefslogtreecommitdiff
path: root/gcc/ubsan.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/ubsan.c')
-rw-r--r--gcc/ubsan.c131
1 files changed, 113 insertions, 18 deletions
diff --git a/gcc/ubsan.c b/gcc/ubsan.c
index 5a8a447..5e1c3e7 100644
--- a/gcc/ubsan.c
+++ b/gcc/ubsan.c
@@ -271,23 +271,24 @@ get_ubsan_type_info_for_type (tree type)
gcc_assert (TYPE_SIZE (type) && tree_fits_uhwi_p (TYPE_SIZE (type)));
if (TREE_CODE (type) == REAL_TYPE)
return tree_to_uhwi (TYPE_SIZE (type));
- else
+ else if (INTEGRAL_TYPE_P (type))
{
int prec = exact_log2 (tree_to_uhwi (TYPE_SIZE (type)));
gcc_assert (prec != -1);
return (prec << 1) | !TYPE_UNSIGNED (type);
}
+ else
+ return 0;
}
/* Helper routine that returns ADDR_EXPR of a VAR_DECL of a type
descriptor. It first looks into the hash table; if not found,
create the VAR_DECL, put it into the hash table and return the
- ADDR_EXPR of it. TYPE describes a particular type. WANT_POINTER_TYPE_P
- means whether we are interested in the pointer type and not the pointer
- itself. */
+ ADDR_EXPR of it. TYPE describes a particular type. PSTYLE is
+ an enum controlling how we want to print the type. */
tree
-ubsan_type_descriptor (tree type, bool want_pointer_type_p)
+ubsan_type_descriptor (tree type, enum ubsan_print_style pstyle)
{
/* See through any typedefs. */
type = TYPE_MAIN_VARIANT (type);
@@ -308,7 +309,7 @@ ubsan_type_descriptor (tree type, bool want_pointer_type_p)
unsigned short tkind, tinfo;
/* Get the name of the type, or the name of the pointer type. */
- if (want_pointer_type_p)
+ if (pstyle == UBSAN_PRINT_POINTER)
{
gcc_assert (POINTER_TYPE_P (type));
type2 = TREE_TYPE (type);
@@ -324,6 +325,12 @@ ubsan_type_descriptor (tree type, bool want_pointer_type_p)
/* If an array, get its type. */
type2 = strip_array_types (type2);
+ if (pstyle == UBSAN_PRINT_ARRAY)
+ {
+ while (POINTER_TYPE_P (type2))
+ deref_depth++, type2 = TREE_TYPE (type2);
+ }
+
if (TYPE_NAME (type2) != NULL)
{
if (TREE_CODE (TYPE_NAME (type2)) == IDENTIFIER_NODE)
@@ -338,7 +345,7 @@ ubsan_type_descriptor (tree type, bool want_pointer_type_p)
/* Decorate the type name with '', '*', "struct", or "union". */
pretty_name = (char *) alloca (strlen (tname) + 16 + deref_depth);
- if (want_pointer_type_p)
+ if (pstyle == UBSAN_PRINT_POINTER)
{
int pos = sprintf (pretty_name, "'%s%s%s%s%s%s%s",
TYPE_VOLATILE (type2) ? "volatile " : "",
@@ -355,6 +362,33 @@ ubsan_type_descriptor (tree type, bool want_pointer_type_p)
pretty_name[pos++] = '\'';
pretty_name[pos] = '\0';
}
+ else if (pstyle == UBSAN_PRINT_ARRAY)
+ {
+ /* Pretty print the array dimensions. */
+ gcc_assert (TREE_CODE (type) == ARRAY_TYPE);
+ tree t = type;
+ int pos = sprintf (pretty_name, "'%s ", tname);
+ while (deref_depth-- > 0)
+ pretty_name[pos++] = '*';
+ while (TREE_CODE (t) == ARRAY_TYPE)
+ {
+ pretty_name[pos++] = '[';
+ tree dom = TYPE_DOMAIN (t);
+ if (dom && TREE_CODE (TYPE_MAX_VALUE (dom)) == INTEGER_CST)
+ pos += sprintf (&pretty_name[pos], HOST_WIDE_INT_PRINT_DEC,
+ tree_to_shwi (TYPE_MAX_VALUE (dom)) + 1);
+ else
+ /* ??? We can't determine the variable name; print VLA unspec. */
+ pretty_name[pos++] = '*';
+ pretty_name[pos++] = ']';
+ t = TREE_TYPE (t);
+ }
+ pretty_name[pos++] = '\'';
+ pretty_name[pos] = '\0';
+
+ /* Save the tree with stripped types. */
+ type = t;
+ }
else
sprintf (pretty_name, "'%s'", tname);
@@ -550,6 +584,69 @@ is_ubsan_builtin_p (tree t)
"__builtin___ubsan_", 18) == 0;
}
+/* Expand the UBSAN_BOUNDS special builtin function. */
+
+void
+ubsan_expand_bounds_ifn (gimple_stmt_iterator *gsi)
+{
+ gimple stmt = gsi_stmt (*gsi);
+ location_t loc = gimple_location (stmt);
+ gcc_assert (gimple_call_num_args (stmt) == 3);
+
+ /* Pick up the arguments of the UBSAN_BOUNDS call. */
+ tree type = TREE_TYPE (TREE_TYPE (gimple_call_arg (stmt, 0)));
+ tree index = gimple_call_arg (stmt, 1);
+ tree orig_index_type = TREE_TYPE (index);
+ tree bound = gimple_call_arg (stmt, 2);
+
+ gimple_stmt_iterator gsi_orig = *gsi;
+
+ /* Create condition "if (index > bound)". */
+ basic_block then_bb, fallthru_bb;
+ gimple_stmt_iterator cond_insert_point
+ = create_cond_insert_point (gsi, 0/*before_p*/, false, true,
+ &then_bb, &fallthru_bb);
+ index = fold_convert (TREE_TYPE (bound), index);
+ index = force_gimple_operand_gsi (&cond_insert_point, index,
+ true/*simple_p*/, NULL_TREE,
+ false/*before*/, GSI_NEW_STMT);
+ gimple g = gimple_build_cond (GT_EXPR, index, bound, NULL_TREE, NULL_TREE);
+ gimple_set_location (g, loc);
+ gsi_insert_after (&cond_insert_point, g, GSI_NEW_STMT);
+
+ /* Generate __ubsan_handle_out_of_bounds call. */
+ *gsi = gsi_after_labels (then_bb);
+ if (flag_sanitize_undefined_trap_on_error)
+ g = gimple_build_call (builtin_decl_explicit (BUILT_IN_TRAP), 0);
+ else
+ {
+ tree data
+ = ubsan_create_data ("__ubsan_out_of_bounds_data", &loc, NULL,
+ ubsan_type_descriptor (type, UBSAN_PRINT_ARRAY),
+ ubsan_type_descriptor (orig_index_type),
+ NULL_TREE);
+ data = build_fold_addr_expr_loc (loc, data);
+ enum built_in_function bcode
+ = flag_sanitize_recover
+ ? BUILT_IN_UBSAN_HANDLE_OUT_OF_BOUNDS
+ : BUILT_IN_UBSAN_HANDLE_OUT_OF_BOUNDS_ABORT;
+ tree fn = builtin_decl_explicit (bcode);
+ tree val = force_gimple_operand_gsi (gsi, ubsan_encode_value (index),
+ true, NULL_TREE, true,
+ GSI_SAME_STMT);
+ g = gimple_build_call (fn, 2, data, val);
+ }
+ gimple_set_location (g, loc);
+ gsi_insert_before (gsi, g, GSI_SAME_STMT);
+
+ /* Get rid of the UBSAN_BOUNDS call from the IR. */
+ unlink_stmt_vdef (stmt);
+ gsi_remove (&gsi_orig, true);
+
+ /* Point GSI to next logical statement. */
+ *gsi = gsi_start_bb (fallthru_bb);
+}
+
/* Expand UBSAN_NULL internal call. */
void
@@ -609,9 +706,11 @@ ubsan_expand_null_ifn (gimple_stmt_iterator gsi)
tree fn = builtin_decl_implicit (bcode);
const struct ubsan_mismatch_data m
= { build_zero_cst (pointer_sized_int_node), ckind };
- tree data = ubsan_create_data ("__ubsan_null_data", &loc, &m,
- ubsan_type_descriptor (TREE_TYPE (ptr),
- true), NULL_TREE);
+ tree data
+ = ubsan_create_data ("__ubsan_null_data", &loc, &m,
+ ubsan_type_descriptor (TREE_TYPE (ptr),
+ UBSAN_PRINT_POINTER),
+ NULL_TREE);
data = build_fold_addr_expr_loc (loc, data);
g = gimple_build_call (fn, 2, data,
build_zero_cst (pointer_sized_int_node));
@@ -689,8 +788,7 @@ ubsan_build_overflow_builtin (tree_code code, location_t loc, tree lhstype,
return build_call_expr_loc (loc, builtin_decl_explicit (BUILT_IN_TRAP), 0);
tree data = ubsan_create_data ("__ubsan_overflow_data", &loc, NULL,
- ubsan_type_descriptor (lhstype, false),
- NULL_TREE);
+ ubsan_type_descriptor (lhstype), NULL_TREE);
enum built_in_function fn_code;
switch (code)
@@ -884,8 +982,7 @@ instrument_bool_enum_load (gimple_stmt_iterator *gsi)
else
{
tree data = ubsan_create_data ("__ubsan_invalid_value_data", &loc, NULL,
- ubsan_type_descriptor (type, false),
- NULL_TREE);
+ ubsan_type_descriptor (type), NULL_TREE);
data = build_fold_addr_expr_loc (loc, data);
enum built_in_function bcode
= flag_sanitize_recover
@@ -1005,10 +1102,8 @@ ubsan_instrument_float_cast (location_t loc, tree type, tree expr)
{
/* Create the __ubsan_handle_float_cast_overflow fn call. */
tree data = ubsan_create_data ("__ubsan_float_cast_overflow_data", NULL,
- NULL,
- ubsan_type_descriptor (expr_type, false),
- ubsan_type_descriptor (type, false),
- NULL_TREE);
+ NULL, ubsan_type_descriptor (expr_type),
+ ubsan_type_descriptor (type), NULL_TREE);
enum built_in_function bcode
= flag_sanitize_recover
? BUILT_IN_UBSAN_HANDLE_FLOAT_CAST_OVERFLOW