diff options
Diffstat (limited to 'gcc/ubsan.c')
-rw-r--r-- | gcc/ubsan.c | 141 |
1 files changed, 139 insertions, 2 deletions
diff --git a/gcc/ubsan.c b/gcc/ubsan.c index 745ca80..e3128ad 100644 --- a/gcc/ubsan.c +++ b/gcc/ubsan.c @@ -1090,6 +1090,7 @@ instrument_bool_enum_load (gimple_stmt_iterator *gsi) } gimple_set_location (g, loc); gsi_insert_before (&gsi2, g, GSI_SAME_STMT); + *gsi = gsi_for_stmt (stmt); } /* Instrument float point-to-integer conversion. TYPE is an integer type of @@ -1215,6 +1216,122 @@ ubsan_instrument_float_cast (location_t loc, tree type, tree expr) fn, integer_zero_node); } +/* Instrument values passed to function arguments with nonnull attribute. */ + +static void +instrument_nonnull_arg (gimple_stmt_iterator *gsi) +{ + gimple stmt = gsi_stmt (*gsi); + location_t loc[2]; + /* infer_nonnull_range needs flag_delete_null_pointer_checks set, + while for nonnull sanitization it is clear. */ + int save_flag_delete_null_pointer_checks = flag_delete_null_pointer_checks; + flag_delete_null_pointer_checks = 1; + loc[0] = gimple_location (stmt); + loc[1] = UNKNOWN_LOCATION; + for (unsigned int i = 0; i < gimple_call_num_args (stmt); i++) + { + tree arg = gimple_call_arg (stmt, i); + if (POINTER_TYPE_P (TREE_TYPE (arg)) + && infer_nonnull_range (stmt, arg, false, true)) + { + gimple g; + if (!is_gimple_val (arg)) + { + g = gimple_build_assign (make_ssa_name (TREE_TYPE (arg), NULL), + arg); + gimple_set_location (g, loc[0]); + gsi_insert_before (gsi, g, GSI_SAME_STMT); + arg = gimple_assign_lhs (g); + } + + basic_block then_bb, fallthru_bb; + *gsi = create_cond_insert_point (gsi, true, false, true, + &then_bb, &fallthru_bb); + g = gimple_build_cond (EQ_EXPR, arg, + build_zero_cst (TREE_TYPE (arg)), + NULL_TREE, NULL_TREE); + gimple_set_location (g, loc[0]); + gsi_insert_after (gsi, g, GSI_NEW_STMT); + + *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_nonnull_arg_data", + 2, loc, NULL_TREE, + build_int_cst (integer_type_node, + i + 1), + NULL_TREE); + data = build_fold_addr_expr_loc (loc[0], data); + enum built_in_function bcode + = flag_sanitize_recover + ? BUILT_IN_UBSAN_HANDLE_NONNULL_ARG + : BUILT_IN_UBSAN_HANDLE_NONNULL_ARG_ABORT; + tree fn = builtin_decl_explicit (bcode); + + g = gimple_build_call (fn, 1, data); + } + gimple_set_location (g, loc[0]); + gsi_insert_before (gsi, g, GSI_SAME_STMT); + } + *gsi = gsi_for_stmt (stmt); + } + flag_delete_null_pointer_checks = save_flag_delete_null_pointer_checks; +} + +/* Instrument returns in functions with returns_nonnull attribute. */ + +static void +instrument_nonnull_return (gimple_stmt_iterator *gsi) +{ + gimple stmt = gsi_stmt (*gsi); + location_t loc[2]; + tree arg = gimple_return_retval (stmt); + /* infer_nonnull_range needs flag_delete_null_pointer_checks set, + while for nonnull return sanitization it is clear. */ + int save_flag_delete_null_pointer_checks = flag_delete_null_pointer_checks; + flag_delete_null_pointer_checks = 1; + loc[0] = gimple_location (stmt); + loc[1] = UNKNOWN_LOCATION; + if (arg + && POINTER_TYPE_P (TREE_TYPE (arg)) + && is_gimple_val (arg) + && infer_nonnull_range (stmt, arg, false, true)) + { + basic_block then_bb, fallthru_bb; + *gsi = create_cond_insert_point (gsi, true, false, true, + &then_bb, &fallthru_bb); + gimple g = gimple_build_cond (EQ_EXPR, arg, + build_zero_cst (TREE_TYPE (arg)), + NULL_TREE, NULL_TREE); + gimple_set_location (g, loc[0]); + gsi_insert_after (gsi, g, GSI_NEW_STMT); + + *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_nonnull_return_data", + 2, loc, NULL_TREE, NULL_TREE); + data = build_fold_addr_expr_loc (loc[0], data); + enum built_in_function bcode + = flag_sanitize_recover + ? BUILT_IN_UBSAN_HANDLE_NONNULL_RETURN + : BUILT_IN_UBSAN_HANDLE_NONNULL_RETURN_ABORT; + tree fn = builtin_decl_explicit (bcode); + + g = gimple_build_call (fn, 1, data); + } + gimple_set_location (g, loc[0]); + gsi_insert_before (gsi, g, GSI_SAME_STMT); + *gsi = gsi_for_stmt (stmt); + } + flag_delete_null_pointer_checks = save_flag_delete_null_pointer_checks; +} + namespace { const pass_data pass_data_ubsan = @@ -1242,7 +1359,9 @@ public: { return flag_sanitize & (SANITIZE_NULL | SANITIZE_SI_OVERFLOW | SANITIZE_BOOL | SANITIZE_ENUM - | SANITIZE_ALIGNMENT) + | SANITIZE_ALIGNMENT + | SANITIZE_NONNULL_ATTRIBUTE + | SANITIZE_RETURNS_NONNULL_ATTRIBUTE) && current_function_decl != NULL_TREE && !lookup_attribute ("no_sanitize_undefined", DECL_ATTRIBUTES (current_function_decl)); @@ -1285,7 +1404,25 @@ pass_ubsan::execute (function *fun) if (flag_sanitize & (SANITIZE_BOOL | SANITIZE_ENUM) && gimple_assign_load_p (stmt)) - instrument_bool_enum_load (&gsi); + { + instrument_bool_enum_load (&gsi); + bb = gimple_bb (stmt); + } + + if ((flag_sanitize & SANITIZE_NONNULL_ATTRIBUTE) + && is_gimple_call (stmt) + && !gimple_call_internal_p (stmt)) + { + instrument_nonnull_arg (&gsi); + bb = gimple_bb (stmt); + } + + if ((flag_sanitize & SANITIZE_RETURNS_NONNULL_ATTRIBUTE) + && gimple_code (stmt) == GIMPLE_RETURN) + { + instrument_nonnull_return (&gsi); + bb = gimple_bb (stmt); + } gsi_next (&gsi); } |