aboutsummaryrefslogtreecommitdiff
path: root/gcc/ubsan.c
diff options
context:
space:
mode:
authorMarek Polacek <mpolacek@gcc.gnu.org>2014-06-20 21:20:51 +0000
committerMarek Polacek <mpolacek@gcc.gnu.org>2014-06-20 21:20:51 +0000
commit0e37a2f33da9dcc33921ded88f700c28dff7960e (patch)
tree909724d7e8bcbb98c38c8f42a5f641e17c4ac7ee /gcc/ubsan.c
parent87681fb55051518fb40426e61ee4fbc2a47073c3 (diff)
downloadgcc-0e37a2f33da9dcc33921ded88f700c28dff7960e.zip
gcc-0e37a2f33da9dcc33921ded88f700c28dff7960e.tar.gz
gcc-0e37a2f33da9dcc33921ded88f700c28dff7960e.tar.bz2
asan.c (pass_sanopt::execute): Handle IFN_UBSAN_BOUNDS.
* asan.c (pass_sanopt::execute): Handle IFN_UBSAN_BOUNDS. * flag-types.h (enum sanitize_code): Add SANITIZE_BOUNDS and or it into SANITIZE_UNDEFINED. * doc/invoke.texi: Describe -fsanitize=bounds. * gimplify.c (gimplify_call_expr): Add gimplification of internal functions created in the FEs. * internal-fn.c: Move "internal-fn.h" after "tree.h". (expand_UBSAN_BOUNDS): New function. * internal-fn.def (UBSAN_BOUNDS): New internal function. * internal-fn.h: Don't define internal functions here. * opts.c (common_handle_option): Add -fsanitize=bounds. * sanitizer.def (BUILT_IN_UBSAN_HANDLE_OUT_OF_BOUNDS, BUILT_IN_UBSAN_HANDLE_OUT_OF_BOUNDS_ABORT): Add. * tree-core.h: Define internal functions here. (struct tree_base): Add ifn field. * tree-pretty-print.c: Include "internal-fn.h". (dump_generic_node): Handle functions without CALL_EXPR_FN. * tree.c (get_callee_fndecl): Likewise. (build_call_expr_internal_loc): New function. * tree.def (CALL_EXPR): Update description. * tree.h (CALL_EXPR_IFN): Define. (build_call_expr_internal_loc): Declare. * ubsan.c (get_ubsan_type_info_for_type): Return 0 for non-arithmetic types. (ubsan_type_descriptor): Change bool parameter to enum ubsan_print_style. Adjust the code. Add handling of UBSAN_PRINT_ARRAY. (ubsan_expand_bounds_ifn): New function. (ubsan_expand_null_ifn): Adjust ubsan_type_descriptor call. (ubsan_build_overflow_builtin): Likewise. (instrument_bool_enum_load): Likewise. (ubsan_instrument_float_cast): Likewise. * ubsan.h (enum ubsan_print_style): New enum. (ubsan_expand_bounds_ifn): Declare. (ubsan_type_descriptor): Adjust declaration. Use a default parameter. c-family/ * c-gimplify.c: Include "c-ubsan.h" and "pointer-set.h". (ubsan_walk_array_refs_r): New function. (c_genericize): Instrument array bounds. * c-ubsan.c: Include "internal-fn.h". (ubsan_instrument_division): Mark instrumented arrays as having side effects. Adjust ubsan_type_descriptor call. (ubsan_instrument_shift): Likewise. (ubsan_instrument_vla): Adjust ubsan_type_descriptor call. (ubsan_instrument_bounds): New function. (ubsan_array_ref_instrumented_p): New function. (ubsan_maybe_instrument_array_ref): New function. * c-ubsan.h (ubsan_instrument_bounds): Declare. (ubsan_array_ref_instrumented_p): Declare. (ubsan_maybe_instrument_array_ref): Declare. testsuite/ * c-c++-common/ubsan/bounds-1.c: New test. * c-c++-common/ubsan/bounds-2.c: New test. * c-c++-common/ubsan/bounds-3.c: New test. * c-c++-common/ubsan/bounds-4.c: New test. * c-c++-common/ubsan/bounds-5.c: New test. * c-c++-common/ubsan/bounds-6.c: New test. From-SVN: r211859
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