aboutsummaryrefslogtreecommitdiff
path: root/gcc/ubsan.c
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2014-09-10 11:23:16 +0200
committerJakub Jelinek <jakub@gcc.gnu.org>2014-09-10 11:23:16 +0200
commit126edc3fe212555ff83e2949b22843ae13299e09 (patch)
tree303e23d283cab6629b540e2e4d7e2702600c3851 /gcc/ubsan.c
parent570a11fe5a60f3012f1c2548745de10fd96b787e (diff)
downloadgcc-126edc3fe212555ff83e2949b22843ae13299e09.zip
gcc-126edc3fe212555ff83e2949b22843ae13299e09.tar.gz
gcc-126edc3fe212555ff83e2949b22843ae13299e09.tar.bz2
flag-types.h (enum sanitize_code): Add SANITIZE_NONNULL_ATTRIBUTE and SANITIZE_RETURNS_NONNULL_ATTRIBUTE...
gcc/ * flag-types.h (enum sanitize_code): Add SANITIZE_NONNULL_ATTRIBUTE and SANITIZE_RETURNS_NONNULL_ATTRIBUTE, or them into SANITIZE_UNDEFINED. * opts.c (common_handle_option): Handle SANITIZE_NONNULL_ATTRIBUTE and SANITIZE_RETURNS_NONNULL_ATTRIBUTE and disable flag_delete_null_pointer_checks for them. * sanitizer.def (BUILT_IN_UBSAN_HANDLE_NONNULL_ARG, BUILT_IN_UBSAN_HANDLE_NONNULL_ARG_ABORT, BUILT_IN_UBSAN_HANDLE_NONNULL_RETURN, BUILT_IN_UBSAN_HANDLE_NONNULL_RETURN_ABORT): New. * ubsan.c (instrument_bool_enum_load): Set *gsi back to stmt's iterator. (instrument_nonnull_arg, instrument_nonnull_return): New functions. (pass_ubsan::gate): Return true even for SANITIZE_NONNULL_ATTRIBUTE or SANITIZE_RETURNS_NONNULL_ATTRIBUTE. (pass_ubsan::execute): Call instrument_nonnull_{arg,return}. * doc/invoke.texi (-fsanitize=nonnull-attribute, -fsanitize=returns-nonnull-attribute): Document. gcc/testsuite/ * c-c++-common/ubsan/attrib-3.c: New test. * c-c++-common/ubsan/nonnull-1.c: New test. * c-c++-common/ubsan/nonnull-2.c: New test. * c-c++-common/ubsan/nonnull-3.c: New test. * c-c++-common/ubsan/nonnull-4.c: New test. * c-c++-common/ubsan/nonnull-5.c: New test. libsanitizer/ * ubsan/ubsan_handlers.cc, ubsan/ubsan_handlers.h: Cherry pick upstream r215485, r217389, r217391 and r217400. From-SVN: r215118
Diffstat (limited to 'gcc/ubsan.c')
-rw-r--r--gcc/ubsan.c141
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);
}