diff options
Diffstat (limited to 'gcc/ubsan.c')
-rw-r--r-- | gcc/ubsan.c | 131 |
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 |