aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc')
-rw-r--r--gcc/builtins.cc9
-rw-r--r--gcc/cgraphunit.cc3
-rw-r--r--gcc/common.opt4
-rw-r--r--gcc/cp/constexpr.cc29
-rw-r--r--gcc/cp/cp-gimplify.cc7
-rw-r--r--gcc/doc/invoke.texi14
-rw-r--r--gcc/gimple-fold.cc7
-rw-r--r--gcc/gimple.cc13
-rw-r--r--gcc/gimple.h1
-rw-r--r--gcc/ipa-fnsummary.cc4
-rw-r--r--gcc/ipa-prop.cc4
-rw-r--r--gcc/ipa.cc3
-rw-r--r--gcc/opts.cc4
-rw-r--r--gcc/sanopt.cc10
-rw-r--r--gcc/testsuite/g++.dg/ubsan/return-8a.C16
-rw-r--r--gcc/testsuite/g++.dg/ubsan/return-8b.C17
-rw-r--r--gcc/testsuite/g++.dg/ubsan/return-8d.C16
-rw-r--r--gcc/testsuite/g++.dg/ubsan/return-8e.C17
-rw-r--r--gcc/tree-cfg.cc7
-rw-r--r--gcc/tree-ssa-loop-ivcanon.cc7
-rw-r--r--gcc/tree-ssa-sccvn.cc2
-rw-r--r--gcc/tree.cc40
-rw-r--r--gcc/tree.h5
-rw-r--r--gcc/ubsan.cc48
-rw-r--r--gcc/ubsan.h1
25 files changed, 233 insertions, 55 deletions
diff --git a/gcc/builtins.cc b/gcc/builtins.cc
index 971b18c..e6816d5 100644
--- a/gcc/builtins.cc
+++ b/gcc/builtins.cc
@@ -5184,6 +5184,9 @@ expand_builtin_trap (void)
static void
expand_builtin_unreachable (void)
{
+ /* Use gimple_build_builtin_unreachable or builtin_decl_unreachable
+ to avoid this. */
+ gcc_checking_assert (!sanitize_flags_p (SANITIZE_UNREACHABLE));
emit_barrier ();
}
@@ -9261,6 +9264,12 @@ fold_builtin_0 (location_t loc, tree fndecl)
case BUILT_IN_CLASSIFY_TYPE:
return fold_builtin_classify_type (NULL_TREE);
+ case BUILT_IN_UNREACHABLE:
+ /* Rewrite any explicit calls to __builtin_unreachable. */
+ if (sanitize_flags_p (SANITIZE_UNREACHABLE))
+ return build_builtin_unreachable (loc);
+ break;
+
default:
break;
}
diff --git a/gcc/cgraphunit.cc b/gcc/cgraphunit.cc
index e77bf97..836e759 100644
--- a/gcc/cgraphunit.cc
+++ b/gcc/cgraphunit.cc
@@ -1033,8 +1033,7 @@ walk_polymorphic_call_targets (hash_set<void *> *reachable_call_targets,
if (targets.length () == 1)
target = targets[0];
else
- target = cgraph_node::create
- (builtin_decl_implicit (BUILT_IN_UNREACHABLE));
+ target = cgraph_node::create (builtin_decl_unreachable ());
if (symtab->dump_file)
{
diff --git a/gcc/common.opt b/gcc/common.opt
index 32917aa..da5d23d 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -3017,6 +3017,10 @@ funit-at-a-time
Common Var(flag_unit_at_a_time) Init(1)
Compile whole compilation unit at a time.
+funreachable-traps
+Common Var(flag_unreachable_traps) Optimization
+Trap on __builtin_unreachable instead of using it for optimization.
+
funroll-loops
Common Var(flag_unroll_loops) Optimization EnabledBy(funroll-all-loops)
Perform loop unrolling when iteration count is known.
diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
index fd7f8c0..0dc94d9 100644
--- a/gcc/cp/constexpr.cc
+++ b/gcc/cp/constexpr.cc
@@ -1438,6 +1438,20 @@ cxx_eval_builtin_function_call (const constexpr_ctx *ctx, tree t, tree fun,
/* These builtins shall be ignored during constant expression
evaluation. */
return void_node;
+ case BUILT_IN_UNREACHABLE:
+ case BUILT_IN_TRAP:
+ if (!*non_constant_p && !ctx->quiet)
+ {
+ /* Do not allow__builtin_unreachable in constexpr function.
+ The __builtin_unreachable call with BUILTINS_LOCATION
+ comes from cp_maybe_instrument_return. */
+ if (EXPR_LOCATION (t) == BUILTINS_LOCATION)
+ error ("%<constexpr%> call flows off the end of the function");
+ else
+ error ("%q+E is not a constant expression", t);
+ }
+ *non_constant_p = true;
+ return t;
default:
break;
}
@@ -1531,18 +1545,9 @@ cxx_eval_builtin_function_call (const constexpr_ctx *ctx, tree t, tree fun,
{
if (!*non_constant_p && !ctx->quiet)
{
- /* Do not allow__builtin_unreachable in constexpr function.
- The __builtin_unreachable call with BUILTINS_LOCATION
- comes from cp_maybe_instrument_return. */
- if (fndecl_built_in_p (fun, BUILT_IN_UNREACHABLE)
- && EXPR_LOCATION (t) == BUILTINS_LOCATION)
- error ("%<constexpr%> call flows off the end of the function");
- else
- {
- new_call = build_call_array_loc (EXPR_LOCATION (t), TREE_TYPE (t),
- CALL_EXPR_FN (t), nargs, args);
- error ("%q+E is not a constant expression", new_call);
- }
+ new_call = build_call_array_loc (EXPR_LOCATION (t), TREE_TYPE (t),
+ CALL_EXPR_FN (t), nargs, args);
+ error ("%q+E is not a constant expression", new_call);
}
*non_constant_p = true;
return t;
diff --git a/gcc/cp/cp-gimplify.cc b/gcc/cp/cp-gimplify.cc
index 6f84d15..c05be83 100644
--- a/gcc/cp/cp-gimplify.cc
+++ b/gcc/cp/cp-gimplify.cc
@@ -1814,7 +1814,7 @@ cp_maybe_instrument_return (tree fndecl)
information is provided, while the __builtin_unreachable () below
if return sanitization is disabled will just result in hard to
understand runtime error without location. */
- && (!optimize
+ && ((!optimize && !flag_unreachable_traps)
|| sanitize_flags_p (SANITIZE_UNREACHABLE, fndecl)))
return;
@@ -1864,10 +1864,7 @@ cp_maybe_instrument_return (tree fndecl)
if (sanitize_flags_p (SANITIZE_RETURN, fndecl))
t = ubsan_instrument_return (loc);
else
- {
- tree fndecl = builtin_decl_explicit (BUILT_IN_UNREACHABLE);
- t = build_call_expr_loc (BUILTINS_LOCATION, fndecl, 0);
- }
+ t = build_builtin_unreachable (BUILTINS_LOCATION);
append_to_statement_list (t, p);
}
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index fb50636..e7526c5 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -12939,6 +12939,20 @@ also at @option{-O0} if @option{-fsection-anchors} is explicitly requested.
Additionally @option{-fno-toplevel-reorder} implies
@option{-fno-section-anchors}.
+@item -funreachable-traps
+@opindex funreachable-traps
+With this option, the compiler turns calls to
+@code{__builtin_unreachable} into traps, instead of using them for
+optimization. This also affects any such calls implicitly generated
+by the compiler.
+
+This option has the same effect as @option{-fsanitize=unreachable
+-fsanitize-trap=unreachable}, but does not affect the values of those
+options. If @option{-fsanitize=unreachable} is enabled, that option
+takes priority over this one.
+
+This option is enabled by default at @option{-O0} and @option{-Og}.
+
@item -fweb
@opindex fweb
Constructs webs as commonly used for register allocation purposes and assign
diff --git a/gcc/gimple-fold.cc b/gcc/gimple-fold.cc
index f61bc87..a170478 100644
--- a/gcc/gimple-fold.cc
+++ b/gcc/gimple-fold.cc
@@ -5510,9 +5510,8 @@ gimple_fold_call (gimple_stmt_iterator *gsi, bool inplace)
}
else
{
- tree fndecl = builtin_decl_implicit (BUILT_IN_UNREACHABLE);
- gimple *new_stmt = gimple_build_call (fndecl, 0);
- gimple_set_location (new_stmt, gimple_location (stmt));
+ location_t loc = gimple_location (stmt);
+ gimple *new_stmt = gimple_build_builtin_unreachable (loc);
/* If the call had a SSA name as lhs morph that into
an uninitialized value. */
if (lhs && TREE_CODE (lhs) == SSA_NAME)
@@ -8396,7 +8395,7 @@ gimple_get_virt_method_for_vtable (HOST_WIDE_INT token,
if (!fn
|| (TREE_CODE (fn) != ADDR_EXPR && TREE_CODE (fn) != FDESC_EXPR)
|| TREE_CODE (TREE_OPERAND (fn, 0)) != FUNCTION_DECL)
- fn = builtin_decl_implicit (BUILT_IN_UNREACHABLE);
+ fn = builtin_decl_unreachable ();
else
{
fn = TREE_OPERAND (fn, 0);
diff --git a/gcc/gimple.cc b/gcc/gimple.cc
index b70ab4d..9b15639 100644
--- a/gcc/gimple.cc
+++ b/gcc/gimple.cc
@@ -44,6 +44,7 @@ along with GCC; see the file COPYING3. If not see
#include "stringpool.h"
#include "attribs.h"
#include "asan.h"
+#include "ubsan.h"
#include "langhooks.h"
#include "attr-fnspec.h"
#include "ipa-modref-tree.h"
@@ -421,6 +422,18 @@ gimple_build_call_from_tree (tree t, tree fnptrtype)
return call;
}
+/* Build a gcall to __builtin_unreachable as rewritten by
+ -fsanitize=unreachable. */
+
+gcall *
+gimple_build_builtin_unreachable (location_t loc)
+{
+ tree data = NULL_TREE;
+ tree fn = sanitize_unreachable_fn (&data, loc);
+ gcall *g = gimple_build_call (fn, data != NULL_TREE, data);
+ gimple_set_location (g, loc);
+ return g;
+}
/* Build a GIMPLE_ASSIGN statement.
diff --git a/gcc/gimple.h b/gcc/gimple.h
index 870629c..1d15ff9 100644
--- a/gcc/gimple.h
+++ b/gcc/gimple.h
@@ -1638,6 +1638,7 @@ extern void maybe_remove_unused_call_args (struct function *, gimple *);
extern bool gimple_inexpensive_call_p (gcall *);
extern bool stmt_can_terminate_bb_p (gimple *);
extern location_t gimple_or_expr_nonartificial_location (gimple *, tree);
+gcall *gimple_build_builtin_unreachable (location_t);
/* Return the disposition for a warning (or all warnings by default)
for a statement. */
diff --git a/gcc/ipa-fnsummary.cc b/gcc/ipa-fnsummary.cc
index b12e7a1..c956445 100644
--- a/gcc/ipa-fnsummary.cc
+++ b/gcc/ipa-fnsummary.cc
@@ -250,8 +250,8 @@ static struct cgraph_edge *
redirect_to_unreachable (struct cgraph_edge *e)
{
struct cgraph_node *callee = !e->inline_failed ? e->callee : NULL;
- struct cgraph_node *target = cgraph_node::get_create
- (builtin_decl_implicit (BUILT_IN_UNREACHABLE));
+ struct cgraph_node *target
+ = cgraph_node::get_create (builtin_decl_unreachable ());
if (e->speculative)
e = cgraph_edge::resolve_speculation (e, target->decl);
diff --git a/gcc/ipa-prop.cc b/gcc/ipa-prop.cc
index c037668..e1fc481 100644
--- a/gcc/ipa-prop.cc
+++ b/gcc/ipa-prop.cc
@@ -3410,7 +3410,7 @@ ipa_make_edge_direct_to_target (struct cgraph_edge *ie, tree target,
ie->caller->dump_name ());
}
- target = builtin_decl_implicit (BUILT_IN_UNREACHABLE);
+ target = builtin_decl_unreachable ();
callee = cgraph_node::get_create (target);
unreachable = true;
}
@@ -3821,7 +3821,7 @@ ipa_impossible_devirt_target (struct cgraph_edge *ie, tree target)
"No devirtualization target in %s\n",
ie->caller->dump_name ());
}
- tree new_target = builtin_decl_implicit (BUILT_IN_UNREACHABLE);
+ tree new_target = builtin_decl_unreachable ();
cgraph_node::get_create (new_target);
return new_target;
}
diff --git a/gcc/ipa.cc b/gcc/ipa.cc
index f53f15f..4d5729f 100644
--- a/gcc/ipa.cc
+++ b/gcc/ipa.cc
@@ -232,8 +232,7 @@ walk_polymorphic_call_targets (hash_set<void *> *reachable_call_targets,
if (targets.length () == 1)
target = targets[0];
else
- target = cgraph_node::get_create
- (builtin_decl_implicit (BUILT_IN_UNREACHABLE));
+ target = cgraph_node::get_create (builtin_decl_unreachable ());
if (dump_enabled_p ())
{
diff --git a/gcc/opts.cc b/gcc/opts.cc
index 959d48d..9982974 100644
--- a/gcc/opts.cc
+++ b/gcc/opts.cc
@@ -1122,6 +1122,10 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set,
opts->x_flag_no_inline = 1;
}
+ /* At -O0 or -Og, turn __builtin_unreachable into a trap. */
+ if (!opts->x_optimize || opts->x_optimize_debug)
+ SET_OPTION_IF_UNSET (opts, opts_set, flag_unreachable_traps, true);
+
/* Pipelining of outer loops is only possible when general pipelining
capabilities are requested. */
if (!opts->x_flag_sel_sched_pipelining)
diff --git a/gcc/sanopt.cc b/gcc/sanopt.cc
index c318763..2b05553 100644
--- a/gcc/sanopt.cc
+++ b/gcc/sanopt.cc
@@ -942,7 +942,15 @@ public:
{}
/* opt_pass methods: */
- virtual bool gate (function *) { return flag_sanitize; }
+ virtual bool gate (function *)
+ {
+ /* SANITIZE_RETURN is handled in the front-end. When trapping,
+ SANITIZE_UNREACHABLE is handled by builtin_decl_unreachable. */
+ unsigned int mask = SANITIZE_RETURN;
+ if (flag_sanitize_trap & SANITIZE_UNREACHABLE)
+ mask |= SANITIZE_UNREACHABLE;
+ return flag_sanitize & ~mask;
+ }
virtual unsigned int execute (function *);
}; // class pass_sanopt
diff --git a/gcc/testsuite/g++.dg/ubsan/return-8a.C b/gcc/testsuite/g++.dg/ubsan/return-8a.C
new file mode 100644
index 0000000..54f1c7b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ubsan/return-8a.C
@@ -0,0 +1,16 @@
+// PR c++/104642
+
+// At -O0 and -Og we default to -funreachable-traps
+// so the below should abort at runtime.
+
+// { dg-do run }
+// { dg-shouldfail { *-*-* } }
+// { dg-additional-options "-O0" }
+
+bool b;
+
+int f() {
+ if (b) return 42;
+} // { dg-warning "-Wreturn-type" }
+
+int main() { f(); }
diff --git a/gcc/testsuite/g++.dg/ubsan/return-8b.C b/gcc/testsuite/g++.dg/ubsan/return-8b.C
new file mode 100644
index 0000000..bdaea60
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ubsan/return-8b.C
@@ -0,0 +1,17 @@
+// PR c++/104642
+
+// With -fsanitize=unreachable we shouldn't optimize away the call to f.
+
+// { dg-do run }
+// { dg-shouldfail { *-*-* } }
+// { dg-additional-options "-O -fsanitize=unreachable" }
+
+bool b;
+
+int f() {
+ if (b) return 42;
+ __builtin_unreachable ();
+ return 24;
+}
+
+int main() { f(); }
diff --git a/gcc/testsuite/g++.dg/ubsan/return-8d.C b/gcc/testsuite/g++.dg/ubsan/return-8d.C
new file mode 100644
index 0000000..7eaded0
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ubsan/return-8d.C
@@ -0,0 +1,16 @@
+// PR c++/104642
+
+// At -O0 and -Og we default to -funreachable-traps
+// so the below should abort at runtime.
+
+// { dg-do run }
+// { dg-shouldfail { *-*-* } }
+// { dg-additional-options "-Og" }
+
+bool b;
+
+int f() {
+ if (b) return 42;
+} // { dg-warning "-Wreturn-type" }
+
+int main() { f(); }
diff --git a/gcc/testsuite/g++.dg/ubsan/return-8e.C b/gcc/testsuite/g++.dg/ubsan/return-8e.C
new file mode 100644
index 0000000..fba402b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ubsan/return-8e.C
@@ -0,0 +1,17 @@
+// PR c++/104642
+
+// At -O0 and -Og we default to -funreachable-traps
+// so the below should abort at runtime.
+
+// { dg-do run }
+// { dg-shouldfail { *-*-* } }
+// { dg-additional-options "-O2" }
+
+bool b;
+
+__attribute__ ((optimize ("Og")))
+int f() {
+ if (b) return 42;
+} // { dg-warning "-Wreturn-type" }
+
+int main() { f(); }
diff --git a/gcc/tree-cfg.cc b/gcc/tree-cfg.cc
index c67c278..734fddd 100644
--- a/gcc/tree-cfg.cc
+++ b/gcc/tree-cfg.cc
@@ -9503,9 +9503,8 @@ pass_warn_function_return::execute (function *fun)
with __builtin_unreachable () call. */
if (optimize && gimple_code (last) == GIMPLE_RETURN)
{
- tree fndecl = builtin_decl_implicit (BUILT_IN_UNREACHABLE);
- gimple *new_stmt = gimple_build_call (fndecl, 0);
- gimple_set_location (new_stmt, gimple_location (last));
+ location_t loc = gimple_location (last);
+ gimple *new_stmt = gimple_build_builtin_unreachable (loc);
gimple_stmt_iterator gsi = gsi_for_stmt (last);
gsi_replace (&gsi, new_stmt, true);
remove_edge (e);
@@ -9834,7 +9833,7 @@ execute_fixup_cfg (void)
{
if (stmt && is_gimple_call (stmt))
gimple_call_set_ctrl_altering (stmt, false);
- tree fndecl = builtin_decl_implicit (BUILT_IN_UNREACHABLE);
+ tree fndecl = builtin_decl_unreachable ();
stmt = gimple_build_call (fndecl, 0);
gimple_stmt_iterator gsi = gsi_last_bb (bb);
gsi_insert_after (&gsi, stmt, GSI_NEW_STMT);
diff --git a/gcc/tree-ssa-loop-ivcanon.cc b/gcc/tree-ssa-loop-ivcanon.cc
index 2ee00a3..6a38b77 100644
--- a/gcc/tree-ssa-loop-ivcanon.cc
+++ b/gcc/tree-ssa-loop-ivcanon.cc
@@ -505,9 +505,8 @@ remove_exits_and_undefined_stmts (class loop *loop, unsigned int npeeled)
&& wi::ltu_p (elt->bound, npeeled))
{
gimple_stmt_iterator gsi = gsi_for_stmt (elt->stmt);
- gcall *stmt = gimple_build_call
- (builtin_decl_implicit (BUILT_IN_UNREACHABLE), 0);
- gimple_set_location (stmt, gimple_location (elt->stmt));
+ location_t loc = gimple_location (elt->stmt);
+ gcall *stmt = gimple_build_builtin_unreachable (loc);
gsi_insert_before (&gsi, stmt, GSI_NEW_STMT);
split_block (gimple_bb (stmt), stmt);
changed = true;
@@ -641,7 +640,7 @@ unloop_loops (bitmap loop_closed_ssa_invalidated,
/* Create new basic block for the latch edge destination and wire
it in. */
- stmt = gimple_build_call (builtin_decl_implicit (BUILT_IN_UNREACHABLE), 0);
+ stmt = gimple_build_builtin_unreachable (locus);
latch_edge = make_edge (latch, create_basic_block (NULL, NULL, latch), flags);
latch_edge->probability = profile_probability::never ();
latch_edge->flags |= flags;
diff --git a/gcc/tree-ssa-sccvn.cc b/gcc/tree-ssa-sccvn.cc
index ed68557..776dccb 100644
--- a/gcc/tree-ssa-sccvn.cc
+++ b/gcc/tree-ssa-sccvn.cc
@@ -6807,7 +6807,7 @@ eliminate_dom_walker::eliminate_stmt (basic_block b, gimple_stmt_iterator *gsi)
if (targets.length () == 1)
fn = targets[0]->decl;
else
- fn = builtin_decl_implicit (BUILT_IN_UNREACHABLE);
+ fn = builtin_decl_unreachable ();
if (dump_enabled_p ())
{
dump_printf_loc (MSG_OPTIMIZED_LOCATIONS, stmt,
diff --git a/gcc/tree.cc b/gcc/tree.cc
index 2bfb674..84000dd 100644
--- a/gcc/tree.cc
+++ b/gcc/tree.cc
@@ -71,6 +71,8 @@ along with GCC; see the file COPYING3. If not see
#include "gimple-range.h"
#include "gomp-constants.h"
#include "dfp.h"
+#include "asan.h"
+#include "ubsan.h"
/* Tree code classes. */
@@ -9649,6 +9651,7 @@ build_common_builtin_nodes (void)
}
if (!builtin_decl_explicit_p (BUILT_IN_UNREACHABLE)
+ || !builtin_decl_explicit_p (BUILT_IN_TRAP)
|| !builtin_decl_explicit_p (BUILT_IN_ABORT))
{
ftype = build_function_type (void_type_node, void_list_node);
@@ -9662,6 +9665,10 @@ build_common_builtin_nodes (void)
local_define_builtin ("__builtin_abort", ftype, BUILT_IN_ABORT,
"abort",
ECF_LEAF | ECF_NORETURN | ECF_CONST | ECF_COLD);
+ if (!builtin_decl_explicit_p (BUILT_IN_TRAP))
+ local_define_builtin ("__builtin_trap", ftype, BUILT_IN_TRAP,
+ "__builtin_trap",
+ ECF_NORETURN | ECF_NOTHROW | ECF_LEAF | ECF_COLD);
}
if (!builtin_decl_explicit_p (BUILT_IN_MEMCPY)
@@ -10779,6 +10786,39 @@ build_alloca_call_expr (tree size, unsigned int align, HOST_WIDE_INT max_size)
}
}
+/* The built-in decl to use to mark code points believed to be unreachable.
+ Typically __builtin_unreachable, but __builtin_trap if
+ -fsanitize=unreachable -fsanitize-trap=unreachable. If only
+ -fsanitize=unreachable, we rely on sanopt to replace calls with the
+ appropriate ubsan function. When building a call directly, use
+ {gimple_},build_builtin_unreachable instead. */
+
+tree
+builtin_decl_unreachable ()
+{
+ enum built_in_function fncode = BUILT_IN_UNREACHABLE;
+
+ if (sanitize_flags_p (SANITIZE_UNREACHABLE)
+ ? (flag_sanitize_trap & SANITIZE_UNREACHABLE)
+ : flag_unreachable_traps)
+ fncode = BUILT_IN_TRAP;
+ /* For non-trapping sanitize, we will rewrite __builtin_unreachable () later,
+ in the sanopt pass. */
+
+ return builtin_decl_explicit (fncode);
+}
+
+/* Build a call to __builtin_unreachable, possibly rewritten by
+ -fsanitize=unreachable. Use this rather than the above when practical. */
+
+tree
+build_builtin_unreachable (location_t loc)
+{
+ tree data = NULL_TREE;
+ tree fn = sanitize_unreachable_fn (&data, loc);
+ return build_call_expr_loc (loc, fn, data != NULL_TREE, data);
+}
+
/* Create a new constant string literal of type ELTYPE[SIZE] (or LEN
if SIZE == -1) and return a tree node representing char* pointer to
it as an ADDR_EXPR (ARRAY_REF (ELTYPE, ...)). When STR is nonnull
diff --git a/gcc/tree.h b/gcc/tree.h
index 507ea25..6f6ad5a 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -5858,6 +5858,11 @@ builtin_decl_implicit (enum built_in_function fncode)
return builtin_info[uns_fncode].decl;
}
+/* For BUILTIN_UNREACHABLE, use one of these or
+ gimple_build_builtin_unreachable instead of one of the above. */
+extern tree builtin_decl_unreachable ();
+extern tree build_builtin_unreachable (location_t);
+
/* Set explicit builtin function nodes and whether it is an implicit
function. */
diff --git a/gcc/ubsan.cc b/gcc/ubsan.cc
index 3aa25b5..f150268 100644
--- a/gcc/ubsan.cc
+++ b/gcc/ubsan.cc
@@ -638,27 +638,43 @@ ubsan_create_data (const char *name, int loccnt, const location_t *ploc, ...)
return var;
}
-/* Instrument the __builtin_unreachable call. We just call the libubsan
- routine instead. */
+/* Shared between *build_builtin_unreachable. */
-bool
-ubsan_instrument_unreachable (gimple_stmt_iterator *gsi)
+tree
+sanitize_unreachable_fn (tree *data, location_t loc)
{
- gimple *g;
- location_t loc = gimple_location (gsi_stmt (*gsi));
-
- if (flag_sanitize_trap & SANITIZE_UNREACHABLE)
- g = gimple_build_call (builtin_decl_explicit (BUILT_IN_TRAP), 0);
+ tree fn = NULL_TREE;
+ bool san = sanitize_flags_p (SANITIZE_UNREACHABLE);
+ if (san
+ ? (flag_sanitize_trap & SANITIZE_UNREACHABLE)
+ : flag_unreachable_traps)
+ {
+ fn = builtin_decl_explicit (BUILT_IN_TRAP);
+ *data = NULL_TREE;
+ }
+ else if (san)
+ {
+ fn = builtin_decl_explicit (BUILT_IN_UBSAN_HANDLE_BUILTIN_UNREACHABLE);
+ *data = ubsan_create_data ("__ubsan_unreachable_data", 1, &loc,
+ NULL_TREE, NULL_TREE);
+ *data = build_fold_addr_expr_loc (loc, *data);
+ }
else
{
- tree data = ubsan_create_data ("__ubsan_unreachable_data", 1, &loc,
- NULL_TREE, NULL_TREE);
- data = build_fold_addr_expr_loc (loc, data);
- tree fn
- = builtin_decl_explicit (BUILT_IN_UBSAN_HANDLE_BUILTIN_UNREACHABLE);
- g = gimple_build_call (fn, 1, data);
+ fn = builtin_decl_explicit (BUILT_IN_UNREACHABLE);
+ *data = NULL_TREE;
}
- gimple_set_location (g, loc);
+ return fn;
+}
+
+/* Rewrite a gcall to __builtin_unreachable for -fsanitize=unreachable. Called
+ by the sanopt pass. */
+
+bool
+ubsan_instrument_unreachable (gimple_stmt_iterator *gsi)
+{
+ location_t loc = gimple_location (gsi_stmt (*gsi));
+ gimple *g = gimple_build_builtin_unreachable (loc);
gsi_replace (gsi, g, false);
return false;
}
diff --git a/gcc/ubsan.h b/gcc/ubsan.h
index 17c5254..71a40a3 100644
--- a/gcc/ubsan.h
+++ b/gcc/ubsan.h
@@ -65,5 +65,6 @@ extern tree ubsan_build_overflow_builtin (tree_code, location_t, tree, tree,
tree, tree *);
extern tree ubsan_instrument_float_cast (location_t, tree, tree);
extern tree ubsan_get_source_location_type (void);
+extern tree sanitize_unreachable_fn (tree *data, location_t loc);
#endif /* GCC_UBSAN_H */