public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH] Add support for -fno-sanitize-recover and -fsanitize-undefined-trap-on-error (PR sanitizer/60275)
@ 2014-04-15 10:12 Jakub Jelinek
  2014-04-23  8:14 ` Richard Biener
  2014-05-15 10:30 ` Richard Sandiford
  0 siblings, 2 replies; 17+ messages in thread
From: Jakub Jelinek @ 2014-04-15 10:12 UTC (permalink / raw)
  To: Richard Biener, Marek Polacek, Dodji Seketeli,
	Konstantin Serebryany, Tobias Burnus
  Cc: gcc-patches

Hi!

This patch adds two new options (compatible with clang) which allow
users to choose the behavior of undefined behavior sanitization.

By default as before, all undefined behaviors (except for
__builtin_unreachable and missing return in C++) continue after reporting
which means that you can get lots of runtime errors from a single program
run and the exit code will not reflect the failure in that case.

With this patch, one can use -fsanitize=undefined -fno-sanitize-recover,
which will report just the first undefined behavior and then exit with
non-zero code.
Or one can use -fsanitize-undefined-trap-on-error, which will just
__builtin_trap () on undefined behavior, not report anything and not require
linking of -lubsan (useful e.g. for the kernel or embedded apps).
If -fsanitize-undefined-trap-on-error, then -f{,no-}sanitize-recover
is ignored, as ub traps, of course only the first undefined behavior will
be "reported" (through the SIGILL/abort).

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

2014-04-15  Jakub Jelinek  <jakub@redhat.com>

	PR sanitizer/60275
	* common.opt (fsanitize-recover, fsanitize-undefined-trap-on-error):
	New options.
	* gcc.c (sanitize_spec_function): Don't return "" for "undefined"
	if flag_sanitize_undefined_trap_on_error.
	* sanitizer.def (BUILT_IN_UBSAN_HANDLE_DIVREM_OVERFLOW_ABORT,
	BUILT_IN_UBSAN_HANDLE_SHIFT_OUT_OF_BOUNDS_ABORT,
	BUILT_IN_UBSAN_HANDLE_VLA_BOUND_NOT_POSITIVE_ABORT,
	BUILT_IN_UBSAN_HANDLE_TYPE_MISMATCH_ABORT,
	BUILT_IN_UBSAN_HANDLE_ADD_OVERFLOW_ABORT,
	BUILT_IN_UBSAN_HANDLE_SUB_OVERFLOW_ABORT,
	BUILT_IN_UBSAN_HANDLE_MUL_OVERFLOW_ABORT,
	BUILT_IN_UBSAN_HANDLE_NEGATE_OVERFLOW_ABORT,
	BUILT_IN_UBSAN_HANDLE_LOAD_INVALID_VALUE_ABORT): New builtins.
	* ubsan.c (ubsan_instrument_unreachable): Return
	__builtin_trap () if flag_sanitize_undefined_trap_on_error.
	(ubsan_expand_null_ifn): Emit __builtin_trap ()
	if flag_sanitize_undefined_trap_on_error and
	__ubsan_handle_type_mismatch_abort if !flag_sanitize_recover.
	(ubsan_expand_null_ifn, ubsan_build_overflow_builtin,
	instrument_bool_enum_load): Emit __builtin_trap () if
	flag_sanitize_undefined_trap_on_error and
	__builtin_handle_*_abort () if !flag_sanitize_recover.
	* doc/invoke.texi (-fsanitize-recover,
	-fsanitize-undefined-trap-on-error): Document.
c-family/
	* c-ubsan.c (ubsan_instrument_return): Return __builtin_trap ()
	if flag_sanitize_undefined_trap_on_error.
	(ubsan_instrument_division, ubsan_instrument_shift,
	ubsan_instrument_vla): Likewise.  Use __ubsan_handle_*_abort ()
	if !flag_sanitize_recover.
testsuite/
	* g++.dg/ubsan/return-2.C: Revert 2014-03-24 changes, add
	-fno-sanitize-recover to dg-options.
	* g++.dg/ubsan/cxx11-shift-1.C: Remove c++11 target restriction,
	add -std=c++11 to dg-options.
	* g++.dg/ubsan/cxx11-shift-2.C: Likewise.
	* g++.dg/ubsan/cxx1y-vla.C: Remove c++1y target restriction,
	add -std=c++1y to dg-options.
	* c-c++-common/ubsan/undefined-1.c: Revert 2014-03-24 changes, add
	-fno-sanitize-recover to dg-options.
	* c-c++-common/ubsan/overflow-sub-1.c: Likewise.
	* c-c++-common/ubsan/vla-4.c: Likewise.
	* c-c++-common/ubsan/pr59503.c: Likewise.
	* c-c++-common/ubsan/vla-3.c: Likewise.
	* c-c++-common/ubsan/save-expr-1.c: Likewise.
	* c-c++-common/ubsan/overflow-add-1.c: Likewise.
	* c-c++-common/ubsan/shift-3.c: Likewise.
	* c-c++-common/ubsan/overflow-1.c: Likewise.
	* c-c++-common/ubsan/overflow-negate-2.c: Likewise.
	* c-c++-common/ubsan/vla-2.c: Likewise.
	* c-c++-common/ubsan/overflow-mul-1.c: Likewise.
	* c-c++-common/ubsan/pr60613-1.c: Likewise.
	* c-c++-common/ubsan/shift-6.c: Likewise.
	* c-c++-common/ubsan/overflow-mul-3.c: Likewise.
	* c-c++-common/ubsan/overflow-add-3.c: New test.
	* c-c++-common/ubsan/overflow-add-4.c: New test.
	* c-c++-common/ubsan/div-by-zero-6.c: New test.
	* c-c++-common/ubsan/div-by-zero-7.c: New test.

--- gcc/common.opt.jj	2014-04-15 09:57:33.400264838 +0200
+++ gcc/common.opt	2014-04-15 10:28:10.554519376 +0200
@@ -862,6 +862,14 @@ fsanitize=
 Common Driver Report Joined
 Select what to sanitize
 
+fsanitize-recover
+Common Report Var(flag_sanitize_recover) Init(1)
+After diagnosing undefined behavior attempt to continue execution
+
+fsanitize-undefined-trap-on-error
+Common Report Var(flag_sanitize_undefined_trap_on_error) Init(0)
+Use trap instead of a library function for undefined behavior sanitization
+
 fasynchronous-unwind-tables
 Common Report Var(flag_asynchronous_unwind_tables) Optimization
 Generate unwind tables that are exact at each instruction boundary
--- gcc/gcc.c.jj	2014-04-15 09:57:33.456264545 +0200
+++ gcc/gcc.c	2014-04-15 10:28:10.555519370 +0200
@@ -8170,7 +8170,8 @@ sanitize_spec_function (int argc, const
   if (strcmp (argv[0], "thread") == 0)
     return (flag_sanitize & SANITIZE_THREAD) ? "" : NULL;
   if (strcmp (argv[0], "undefined") == 0)
-    return (flag_sanitize & SANITIZE_UNDEFINED) ? "" : NULL;
+    return ((flag_sanitize & SANITIZE_UNDEFINED)
+	    && !flag_sanitize_undefined_trap_on_error) ? "" : NULL;
   if (strcmp (argv[0], "leak") == 0)
     return ((flag_sanitize
 	     & (SANITIZE_ADDRESS | SANITIZE_LEAK | SANITIZE_THREAD))
--- gcc/sanitizer.def.jj	2014-04-15 09:57:32.819267872 +0200
+++ gcc/sanitizer.def	2014-04-15 10:28:10.556519365 +0200
@@ -335,3 +335,39 @@ DEF_SANITIZER_BUILTIN(BUILT_IN_UBSAN_HAN
 		      "__ubsan_handle_load_invalid_value",
 		      BT_FN_VOID_PTR_PTR,
 		      ATTR_COLD_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN(BUILT_IN_UBSAN_HANDLE_DIVREM_OVERFLOW_ABORT,
+		      "__ubsan_handle_divrem_overflow_abort",
+		      BT_FN_VOID_PTR_PTR_PTR,
+		      ATTR_COLD_NORETURN_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN(BUILT_IN_UBSAN_HANDLE_SHIFT_OUT_OF_BOUNDS_ABORT,
+		      "__ubsan_handle_shift_out_of_bounds_abort",
+		      BT_FN_VOID_PTR_PTR_PTR,
+		      ATTR_COLD_NORETURN_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN(BUILT_IN_UBSAN_HANDLE_VLA_BOUND_NOT_POSITIVE_ABORT,
+		      "__ubsan_handle_vla_bound_not_positive_abort",
+		      BT_FN_VOID_PTR_PTR,
+		      ATTR_COLD_NORETURN_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN(BUILT_IN_UBSAN_HANDLE_TYPE_MISMATCH_ABORT,
+		      "__ubsan_handle_type_mismatch_abort",
+		      BT_FN_VOID_PTR_PTR,
+		      ATTR_COLD_NORETURN_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN(BUILT_IN_UBSAN_HANDLE_ADD_OVERFLOW_ABORT,
+		      "__ubsan_handle_add_overflow_abort",
+		      BT_FN_VOID_PTR_PTR_PTR,
+		      ATTR_COLD_NORETURN_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN(BUILT_IN_UBSAN_HANDLE_SUB_OVERFLOW_ABORT,
+		      "__ubsan_handle_sub_overflow_abort",
+		      BT_FN_VOID_PTR_PTR_PTR,
+		      ATTR_COLD_NORETURN_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN(BUILT_IN_UBSAN_HANDLE_MUL_OVERFLOW_ABORT,
+		      "__ubsan_handle_mul_overflow_abort",
+		      BT_FN_VOID_PTR_PTR_PTR,
+		      ATTR_COLD_NORETURN_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN(BUILT_IN_UBSAN_HANDLE_NEGATE_OVERFLOW_ABORT,
+		      "__ubsan_handle_negate_overflow_abort",
+		      BT_FN_VOID_PTR_PTR,
+		      ATTR_COLD_NORETURN_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN(BUILT_IN_UBSAN_HANDLE_LOAD_INVALID_VALUE_ABORT,
+		      "__ubsan_handle_load_invalid_value_abort",
+		      BT_FN_VOID_PTR_PTR,
+		      ATTR_COLD_NORETURN_NOTHROW_LEAF_LIST)
--- gcc/ubsan.c.jj	2014-04-15 09:57:33.317265271 +0200
+++ gcc/ubsan.c	2014-04-15 10:28:10.556519365 +0200
@@ -516,6 +516,9 @@ ubsan_create_data (const char *name, con
 tree
 ubsan_instrument_unreachable (location_t loc)
 {
+  if (flag_sanitize_undefined_trap_on_error)
+    return build_call_expr_loc (loc, builtin_decl_explicit (BUILT_IN_TRAP), 0);
+
   initialize_sanitizer_builtins ();
   tree data = ubsan_create_data ("__ubsan_unreachable_data", &loc, NULL,
 				 NULL_TREE);
@@ -583,16 +586,25 @@ ubsan_expand_null_ifn (gimple_stmt_itera
     set_immediate_dominator (CDI_DOMINATORS, then_bb, cond_bb);
 
   /* Put the ubsan builtin call into the newly created BB.  */
-  tree fn = builtin_decl_implicit (BUILT_IN_UBSAN_HANDLE_TYPE_MISMATCH);
-  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);
-  data = build_fold_addr_expr_loc (loc, data);
-  gimple g = gimple_build_call (fn, 2, data,
-				build_zero_cst (pointer_sized_int_node));
+  gimple g;
+  if (flag_sanitize_undefined_trap_on_error)
+    g = gimple_build_call (builtin_decl_implicit (BUILT_IN_TRAP), 0);
+  else
+    {
+      enum built_in_function bcode
+	= flag_sanitize_recover
+	  ? BUILT_IN_UBSAN_HANDLE_TYPE_MISMATCH
+	  : BUILT_IN_UBSAN_HANDLE_TYPE_MISMATCH_ABORT;
+      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);
+      data = build_fold_addr_expr_loc (loc, data);
+      g = gimple_build_call (fn, 2, data,
+			     build_zero_cst (pointer_sized_int_node));
+    }
   gimple_set_location (g, loc);
   gimple_stmt_iterator gsi2 = gsi_start_bb (then_bb);
   gsi_insert_after (&gsi2, g, GSI_NEW_STMT);
@@ -662,6 +674,9 @@ tree
 ubsan_build_overflow_builtin (tree_code code, location_t loc, tree lhstype,
 			      tree op0, tree op1)
 {
+  if (flag_sanitize_undefined_trap_on_error)
+    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);
@@ -670,16 +685,24 @@ ubsan_build_overflow_builtin (tree_code
   switch (code)
     {
     case PLUS_EXPR:
-      fn_code = BUILT_IN_UBSAN_HANDLE_ADD_OVERFLOW;
+      fn_code = flag_sanitize_recover
+		? BUILT_IN_UBSAN_HANDLE_ADD_OVERFLOW
+		: BUILT_IN_UBSAN_HANDLE_ADD_OVERFLOW_ABORT;
       break;
     case MINUS_EXPR:
-      fn_code = BUILT_IN_UBSAN_HANDLE_SUB_OVERFLOW;
+      fn_code = flag_sanitize_recover
+		? BUILT_IN_UBSAN_HANDLE_SUB_OVERFLOW
+		: BUILT_IN_UBSAN_HANDLE_SUB_OVERFLOW_ABORT;
       break;
     case MULT_EXPR:
-      fn_code = BUILT_IN_UBSAN_HANDLE_MUL_OVERFLOW;
+      fn_code = flag_sanitize_recover
+		? BUILT_IN_UBSAN_HANDLE_MUL_OVERFLOW
+		: BUILT_IN_UBSAN_HANDLE_MUL_OVERFLOW_ABORT;
       break;
     case NEGATE_EXPR:
-      fn_code = BUILT_IN_UBSAN_HANDLE_NEGATE_OVERFLOW;
+      fn_code = flag_sanitize_recover
+		? BUILT_IN_UBSAN_HANDLE_NEGATE_OVERFLOW
+		: BUILT_IN_UBSAN_HANDLE_NEGATE_OVERFLOW_ABORT;
       break;
     default:
       gcc_unreachable ();
@@ -844,17 +867,26 @@ instrument_bool_enum_load (gimple_stmt_i
   gimple_assign_set_rhs_with_ops (&gsi2, NOP_EXPR, urhs, NULL_TREE);
   update_stmt (stmt);
 
-  tree data = ubsan_create_data ("__ubsan_invalid_value_data",
-				 &loc, NULL,
-				 ubsan_type_descriptor (type, false),
-				 NULL_TREE);
-  data = build_fold_addr_expr_loc (loc, data);
-  tree fn = builtin_decl_explicit (BUILT_IN_UBSAN_HANDLE_LOAD_INVALID_VALUE);
-
   gsi2 = gsi_after_labels (then_bb);
-  tree val = force_gimple_operand_gsi (&gsi2, ubsan_encode_value (urhs),
-				       true, NULL_TREE, true, GSI_SAME_STMT);
-  g = gimple_build_call (fn, 2, data, val);
+  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_invalid_value_data", &loc, NULL,
+				     ubsan_type_descriptor (type, false),
+				     NULL_TREE);
+      data = build_fold_addr_expr_loc (loc, data);
+      enum built_in_function bcode
+	= flag_sanitize_recover
+	  ? BUILT_IN_UBSAN_HANDLE_LOAD_INVALID_VALUE
+	  : BUILT_IN_UBSAN_HANDLE_LOAD_INVALID_VALUE_ABORT;
+      tree fn = builtin_decl_explicit (bcode);
+
+      tree val = force_gimple_operand_gsi (&gsi2, ubsan_encode_value (urhs),
+					   true, NULL_TREE, true,
+					   GSI_SAME_STMT);
+      g = gimple_build_call (fn, 2, data, val);
+    }
   gimple_set_location (g, loc);
   gsi_insert_before (&gsi2, g, GSI_SAME_STMT);
 }
--- gcc/c-family/c-ubsan.c.jj	2014-04-15 09:57:33.362265036 +0200
+++ gcc/c-family/c-ubsan.c	2014-04-15 10:28:10.556519365 +0200
@@ -73,14 +73,22 @@ ubsan_instrument_division (location_t lo
   /* In case we have a SAVE_EXPR in a conditional context, we need to
      make sure it gets evaluated before the condition.  */
   t = fold_build2 (COMPOUND_EXPR, TREE_TYPE (t), op0, t);
-  tree data = ubsan_create_data ("__ubsan_overflow_data",
-				 &loc, NULL,
-				 ubsan_type_descriptor (type, false),
-				 NULL_TREE);
-  data = build_fold_addr_expr_loc (loc, data);
-  tt = builtin_decl_explicit (BUILT_IN_UBSAN_HANDLE_DIVREM_OVERFLOW);
-  tt = build_call_expr_loc (loc, tt, 3, data, ubsan_encode_value (op0),
-			    ubsan_encode_value (op1));
+  if (flag_sanitize_undefined_trap_on_error)
+    tt = build_call_expr_loc (loc, builtin_decl_explicit (BUILT_IN_TRAP), 0);
+  else
+    {
+      tree data = ubsan_create_data ("__ubsan_overflow_data", &loc, NULL,
+				     ubsan_type_descriptor (type, false),
+				     NULL_TREE);
+      data = build_fold_addr_expr_loc (loc, data);
+      enum built_in_function bcode
+	= flag_sanitize_recover
+	  ? BUILT_IN_UBSAN_HANDLE_DIVREM_OVERFLOW
+	  : BUILT_IN_UBSAN_HANDLE_DIVREM_OVERFLOW_ABORT;
+      tt = builtin_decl_explicit (bcode);
+      tt = build_call_expr_loc (loc, tt, 3, data, ubsan_encode_value (op0),
+				ubsan_encode_value (op1));
+    }
   t = fold_build3 (COND_EXPR, void_type_node, t, tt, void_zero_node);
 
   return t;
@@ -142,19 +150,28 @@ ubsan_instrument_shift (location_t loc,
   /* In case we have a SAVE_EXPR in a conditional context, we need to
      make sure it gets evaluated before the condition.  */
   t = fold_build2 (COMPOUND_EXPR, TREE_TYPE (t), op0, t);
-  tree data = ubsan_create_data ("__ubsan_shift_data",
-				 &loc, NULL,
-				 ubsan_type_descriptor (type0, false),
-				 ubsan_type_descriptor (type1, false),
-				 NULL_TREE);
-
-  data = build_fold_addr_expr_loc (loc, data);
-
   t = fold_build2 (TRUTH_OR_EXPR, boolean_type_node, t,
 		   tt ? tt : integer_zero_node);
-  tt = builtin_decl_explicit (BUILT_IN_UBSAN_HANDLE_SHIFT_OUT_OF_BOUNDS);
-  tt = build_call_expr_loc (loc, tt, 3, data, ubsan_encode_value (op0),
-			    ubsan_encode_value (op1));
+
+  if (flag_sanitize_undefined_trap_on_error)
+    tt = build_call_expr_loc (loc, builtin_decl_explicit (BUILT_IN_TRAP), 0);
+  else
+    {
+      tree data = ubsan_create_data ("__ubsan_shift_data", &loc, NULL,
+				     ubsan_type_descriptor (type0, false),
+				     ubsan_type_descriptor (type1, false),
+				     NULL_TREE);
+
+      data = build_fold_addr_expr_loc (loc, data);
+
+      enum built_in_function bcode
+	= flag_sanitize_recover
+	  ? BUILT_IN_UBSAN_HANDLE_SHIFT_OUT_OF_BOUNDS
+	  : BUILT_IN_UBSAN_HANDLE_SHIFT_OUT_OF_BOUNDS_ABORT;
+      tt = builtin_decl_explicit (bcode);
+      tt = build_call_expr_loc (loc, tt, 3, data, ubsan_encode_value (op0),
+				ubsan_encode_value (op1));
+    }
   t = fold_build3 (COND_EXPR, void_type_node, t, tt, void_zero_node);
 
   return t;
@@ -169,13 +186,21 @@ ubsan_instrument_vla (location_t loc, tr
   tree t, tt;
 
   t = fold_build2 (LE_EXPR, boolean_type_node, size, build_int_cst (type, 0));
-  tree data = ubsan_create_data ("__ubsan_vla_data",
-				 &loc, NULL,
-				 ubsan_type_descriptor (type, false),
-				 NULL_TREE);
-  data = build_fold_addr_expr_loc (loc, data);
-  tt = builtin_decl_explicit (BUILT_IN_UBSAN_HANDLE_VLA_BOUND_NOT_POSITIVE);
-  tt = build_call_expr_loc (loc, tt, 2, data, ubsan_encode_value (size));
+  if (flag_sanitize_undefined_trap_on_error)
+    tt = build_call_expr_loc (loc, builtin_decl_explicit (BUILT_IN_TRAP), 0);
+  else
+    {
+      tree data = ubsan_create_data ("__ubsan_vla_data", &loc, NULL,
+				     ubsan_type_descriptor (type, false),
+				     NULL_TREE);
+      data = build_fold_addr_expr_loc (loc, data);
+      enum built_in_function bcode
+	= flag_sanitize_recover
+	  ? BUILT_IN_UBSAN_HANDLE_VLA_BOUND_NOT_POSITIVE
+	  : BUILT_IN_UBSAN_HANDLE_VLA_BOUND_NOT_POSITIVE_ABORT;
+      tt = builtin_decl_explicit (bcode);
+      tt = build_call_expr_loc (loc, tt, 2, data, ubsan_encode_value (size));
+    }
   t = fold_build3 (COND_EXPR, void_type_node, t, tt, void_zero_node);
 
   return t;
@@ -186,6 +211,8 @@ ubsan_instrument_vla (location_t loc, tr
 tree
 ubsan_instrument_return (location_t loc)
 {
+  if (flag_sanitize_undefined_trap_on_error)
+    return build_call_expr_loc (loc, builtin_decl_explicit (BUILT_IN_TRAP), 0);
   /* It is possible that PCH zapped table with definitions of sanitizer
      builtins.  Reinitialize them if needed.  */
   initialize_sanitizer_builtins ();
--- gcc/doc/invoke.texi.jj	2014-04-15 09:57:52.000000000 +0200
+++ gcc/doc/invoke.texi	2014-04-15 12:09:17.983858622 +0200
@@ -288,7 +288,8 @@ Objective-C and Objective-C++ Dialects}.
 @item Debugging Options
 @xref{Debugging Options,,Options for Debugging Your Program or GCC}.
 @gccoptlist{-d@var{letters}  -dumpspecs  -dumpmachine  -dumpversion @gol
--fsanitize=@var{style} @gol
+-fsanitize=@var{style} -fsanitize-recover @gol
+-fsanitize-undefined-trap-on-error @gol
 -fdbg-cnt-list -fdbg-cnt=@var{counter-value-list} @gol
 -fdisable-ipa-@var{pass_name} @gol
 -fdisable-rtl-@var{pass_name} @gol
@@ -5380,6 +5381,26 @@ While @option{-ftrapv} causes traps for
 @option{-fsanitize=undefined} gives a diagnostic message.
 This currently works only for the C family of languages.
 
+@item -fsanitize-recover
+@opindex fsanitize-recover
+By default @option{-fsanitize=undefined} sanitization (and its suboptions
+except for @option{-fsanitize=unreachable} and @option{-fsanitize=return})
+after reporting undefined behavior attempts to continue running the
+program as if no undefined behavior happened.  This means multiple undefined
+behavior runtime errors can be reported in a single program run, and the exit
+code of the program may indicate success even when undefined behavior
+has been reported.  The @option{-fno-sanitize-recover} can be used to alter
+this behavior, only the first detected undefined behavior will be reported
+and program will exit after that with non-zero exit code.
+
+@item -fsanitize-undefined-trap-on-error
+@opindex fsanitize-undefined-trap-on-error
+The @option{-fsanitize-undefined-trap-on-error} instructs the compiler to
+report undefined behavior using @code{__builtin_trap ()} rather than
+a @code{libubsan} library routine.  The advantage of this is that the
+@code{libubsan} library is not needed and will not be linked in, so this
+is usable even for use in freestanding environments.
+
 @item -fdump-final-insns@r{[}=@var{file}@r{]}
 @opindex fdump-final-insns
 Dump the final internal representation (RTL) to @var{file}.  If the
--- gcc/testsuite/g++.dg/ubsan/return-2.C.jj	2014-03-25 09:22:04.311136241 +0100
+++ gcc/testsuite/g++.dg/ubsan/return-2.C	2014-04-15 11:42:41.504233228 +0200
@@ -1,7 +1,5 @@
 // { dg-do run }
-// { dg-options "-fsanitize=return" }
-
-#include <stdio.h>
+// { dg-options "-fsanitize=return -fno-sanitize-recover" }
 
 struct S { S (); ~S (); };
 
@@ -22,12 +20,6 @@ foo (int x)
 int
 main ()
 {
-  fputs ("UBSAN TEST START\n", stderr);
-
   foo (1);
   foo (14);
-
-  fputs ("UBSAN TEST END\n", stderr);
 }
-
-/* { dg-output "UBSAN TEST START(\n|\r\n|\r)UBSAN TEST END" } */
--- gcc/testsuite/g++.dg/ubsan/cxx11-shift-1.C.jj	2014-03-25 09:22:04.331136134 +0100
+++ gcc/testsuite/g++.dg/ubsan/cxx11-shift-1.C	2014-04-15 11:42:44.652216672 +0200
@@ -1,18 +1,10 @@
-/* { dg-do run { target c++11 } } */
-/* { dg-options "-fsanitize=shift -w" } */
-
-#include <stdio.h>
+/* { dg-do run } */
+/* { dg-options "-fsanitize=shift -w -fno-sanitize-recover -std=c++11" } */
 
 int
 main (void)
 {
-  fputs ("UBSAN TEST START\n", stderr);
-
   int a = 1;
   a <<= 31;
-
-  fputs ("UBSAN TEST END\n", stderr);
   return 0;
 }
-
-/* { dg-output "UBSAN TEST START(\n|\r\n|\r)UBSAN TEST END" } */
--- gcc/testsuite/g++.dg/ubsan/cxx11-shift-2.C.jj	2014-03-10 10:49:56.000000000 +0100
+++ gcc/testsuite/g++.dg/ubsan/cxx11-shift-2.C	2014-04-15 11:28:18.777735556 +0200
@@ -1,5 +1,5 @@
-/* { dg-do run { target c++11 } } */
-/* { dg-options "-fsanitize=shift -w" } */
+/* { dg-do run } */
+/* { dg-options "-fsanitize=shift -w -std=c++11" } */
 
 int
 main (void)
--- gcc/testsuite/g++.dg/ubsan/cxx1y-vla.C.jj	2014-03-10 10:49:56.000000000 +0100
+++ gcc/testsuite/g++.dg/ubsan/cxx1y-vla.C	2014-04-15 11:28:40.570622975 +0200
@@ -1,5 +1,5 @@
-/* { dg-do run { target c++1y } } */
-/* { dg-options "-fsanitize=vla-bound -Wall -Wno-unused-variable" } */
+/* { dg-do run } */
+/* { dg-options "-fsanitize=vla-bound -Wall -Wno-unused-variable -std=c++1y" } */
 /* { dg-shouldfail "ubsan" } */
 
 int
--- gcc/testsuite/c-c++-common/ubsan/undefined-1.c.jj	2014-03-25 09:22:05.226131391 +0100
+++ gcc/testsuite/c-c++-common/ubsan/undefined-1.c	2014-04-15 11:43:04.064114597 +0200
@@ -1,7 +1,5 @@
 /* { dg-do run } */
-/* { dg-options "-fsanitize=undefined" } */
-
-#include <stdio.h>
+/* { dg-options "-fsanitize=undefined -fno-sanitize-recover" } */
 
 int
 foo (int x, int y)
@@ -21,13 +19,7 @@ bar (int x, int y)
 int
 main (void)
 {
-  fputs ("UBSAN TEST START\n", stderr);
-
   foo (3, 2);
   bar (12, 42);
-
-  fputs ("UBSAN TEST END\n", stderr);
   return 0;
 }
-
-/* { dg-output "UBSAN TEST START(\n|\r\n|\r)UBSAN TEST END" } */
--- gcc/testsuite/c-c++-common/ubsan/overflow-sub-1.c.jj	2014-03-25 09:22:05.225131396 +0100
+++ gcc/testsuite/c-c++-common/ubsan/overflow-sub-1.c	2014-04-15 11:43:09.677085087 +0200
@@ -1,7 +1,5 @@
 /* { dg-do run } */
-/* { dg-options "-fsanitize=signed-integer-overflow -Wno-unused-variable" } */
-
-#include <stdio.h>
+/* { dg-options "-fsanitize=signed-integer-overflow -Wno-unused-variable -fno-sanitize-recover" } */
 
 #define SCHAR_MAX __SCHAR_MAX__
 #define SCHAR_MIN (-__SCHAR_MAX__ - 1)
@@ -20,8 +18,6 @@ check (int i, int j)
 int
 main (void)
 {
-  fputs ("UBSAN TEST START\n", stderr);
-
 #if __INT_MAX__ == 2147483647
   /* Here, nothing should fail.  */
   volatile int i = -1;
@@ -61,9 +57,5 @@ main (void)
   d--;
   check (d, 32767);
 #endif
-
-  fputs ("UBSAN TEST END\n", stderr);
   return 0;
 }
-
-/* { dg-output "UBSAN TEST START(\n|\r\n|\r)UBSAN TEST END" } */
--- gcc/testsuite/c-c++-common/ubsan/vla-4.c.jj	2014-03-25 09:22:05.224131402 +0100
+++ gcc/testsuite/c-c++-common/ubsan/vla-4.c	2014-04-15 11:43:12.250071561 +0200
@@ -1,21 +1,13 @@
 /* { dg-do run } */
-/* { dg-options "-fsanitize=vla-bound" } */
-
-#include <stdio.h>
+/* { dg-options "-fsanitize=vla-bound -fno-sanitize-recover" } */
 
 int
 main (void)
 {
-  fputs ("UBSAN TEST START\n", stderr);
-
   int x = 1;
   /* Check that the size of an array is evaluated only once.  */
   int a[++x];
   if (x != 2)
     __builtin_abort ();
-
-  fputs ("UBSAN TEST END\n", stderr);
   return 0;
 }
-
-/* { dg-output "UBSAN TEST START(\n|\r\n|\r)UBSAN TEST END" } */
--- gcc/testsuite/c-c++-common/ubsan/pr59503.c.jj	2014-03-25 09:22:05.225131396 +0100
+++ gcc/testsuite/c-c++-common/ubsan/pr59503.c	2014-04-15 11:43:14.520059628 +0200
@@ -1,21 +1,13 @@
 /* { dg-do run } */
-/* { dg-options "-fsanitize=signed-integer-overflow" } */
-
-#include <stdio.h>
+/* { dg-options "-fsanitize=signed-integer-overflow -fno-sanitize-recover" } */
 
 int
 main (void)
 {
-  fputs ("UBSAN TEST START\n", stderr);
-
   long long int a = 14;
   long int b = 9;
   asm volatile ("" : "+r" (a), "+r" (b));
   if ((a - b) != 5)
     __builtin_abort ();
-
-  fputs ("UBSAN TEST END\n", stderr);
   return 0;
 }
-
-/* { dg-output "UBSAN TEST START(\n|\r\n|\r)UBSAN TEST END" } */
--- gcc/testsuite/c-c++-common/ubsan/vla-3.c.jj	2014-03-25 09:22:05.224131402 +0100
+++ gcc/testsuite/c-c++-common/ubsan/vla-3.c	2014-04-15 11:43:16.707048131 +0200
@@ -1,7 +1,5 @@
 /* { dg-do run } */
-/* { dg-options "-fsanitize=vla-bound" } */
-
-#include <stdio.h>
+/* { dg-options "-fsanitize=vla-bound -fno-sanitize-recover" } */
 
 /* Don't instrument the arrays here.  */
 int
@@ -13,13 +11,7 @@ foo (int n, int a[])
 int
 main (void)
 {
-  fputs ("UBSAN TEST START\n", stderr);
-
   int a[6] = { };
   int ret = foo (3, a);
-
-  fputs ("UBSAN TEST END\n", stderr);
   return ret;
 }
-
-/* { dg-output "UBSAN TEST START(\n|\r\n|\r)UBSAN TEST END" } */
--- gcc/testsuite/c-c++-common/ubsan/save-expr-1.c.jj	2014-03-25 09:22:05.217131440 +0100
+++ gcc/testsuite/c-c++-common/ubsan/save-expr-1.c	2014-04-15 11:43:19.240034816 +0200
@@ -1,19 +1,11 @@
 /* { dg-do compile } */
-/* { dg-options "-fsanitize=shift -Wall -Werror -O" } */
-
-#include <stdio.h>
+/* { dg-options "-fsanitize=shift -Wall -Werror -O -fno-sanitize-recover" } */
 
 static int x;
 int
 main (void)
 {
-  fputs ("UBSAN TEST START\n", stderr);
-
   int o = 1;
   int y = x << o;
-
-  fputs ("UBSAN TEST END\n", stderr);
   return y;
 }
-
-/* { dg-output "UBSAN TEST START(\n|\r\n|\r)UBSAN TEST END" } */
--- gcc/testsuite/c-c++-common/ubsan/overflow-add-1.c.jj	2014-03-25 09:22:05.225131396 +0100
+++ gcc/testsuite/c-c++-common/ubsan/overflow-add-1.c	2014-04-15 11:43:22.331018569 +0200
@@ -1,7 +1,5 @@
 /* { dg-do run } */
-/* { dg-options "-fsanitize=signed-integer-overflow -Wno-unused-variable" } */
-
-#include <stdio.h>
+/* { dg-options "-fsanitize=signed-integer-overflow -Wno-unused-variable -fno-sanitize-recover" } */
 
 #define SCHAR_MAX __SCHAR_MAX__
 #define SHRT_MAX __SHRT_MAX__
@@ -18,8 +16,6 @@ check (int i, int j)
 int
 main (void)
 {
-  fputs ("UBSAN TEST START\n", stderr);
-
 #if __INT_MAX__ == 2147483647
   /* Here, nothing should fail.  */
   volatile int j = INT_MAX;
@@ -59,9 +55,5 @@ main (void)
   d++;
   check (d, -32768);
 #endif
-
-  fputs ("UBSAN TEST END\n", stderr);
   return 0;
 }
-
-/* { dg-output "UBSAN TEST START(\n|\r\n|\r)UBSAN TEST END" } */
--- gcc/testsuite/c-c++-common/ubsan/shift-3.c.jj	2014-03-25 09:22:05.227131385 +0100
+++ gcc/testsuite/c-c++-common/ubsan/shift-3.c	2014-04-15 11:43:24.323008099 +0200
@@ -1,19 +1,11 @@
 /* { dg-do run } */
-/* { dg-options "-fsanitize=shift -w" } */
-
-#include <stdio.h>
+/* { dg-options "-fsanitize=shift -w -fno-sanitize-recover" } */
 
 int
 main (void)
 {
-  fputs ("UBSAN TEST START\n", stderr);
-
   unsigned int a = 1;
   a <<= 31;
   a <<= 1;
-
-  fputs ("UBSAN TEST END\n", stderr);
   return 0;
 }
-
-/* { dg-output "UBSAN TEST START(\n|\r\n|\r)UBSAN TEST END" } */
--- gcc/testsuite/c-c++-common/ubsan/overflow-1.c.jj	2014-03-25 09:22:05.000000000 +0100
+++ gcc/testsuite/c-c++-common/ubsan/overflow-1.c	2014-04-15 11:43:30.257976905 +0200
@@ -1,7 +1,5 @@
 /* { dg-do run } */
-/* { dg-options "-fsanitize=signed-integer-overflow" } */
-
-#include <stdio.h>
+/* { dg-options "-fsanitize=signed-integer-overflow -fno-sanitize-recover" } */
 
 #ifndef ASM1
 # define ASM1(a) /* Nothing */
@@ -53,8 +51,6 @@
 int
 main (void)
 {
-  fputs ("UBSAN TEST START\n", stderr);
-
   CHECK (FN1 (char, char, +), 23);
   CHECK (FN1 (char, char, -), 5);
   CHECK (FN1 (char, char, *), 126);
@@ -261,9 +257,5 @@ main (void)
   CHECK (FN5 (unsigned long int), -77);
   CHECK (FN5 (long long int), -77);
   CHECK (FN5 (unsigned long long int), -77);
-
-  fputs ("UBSAN TEST END\n", stderr);
   return 0;
 }
-
-/* { dg-output "UBSAN TEST START(\n|\r\n|\r)UBSAN TEST END" } */
--- gcc/testsuite/c-c++-common/ubsan/overflow-negate-2.c.jj	2014-03-25 09:22:05.227131385 +0100
+++ gcc/testsuite/c-c++-common/ubsan/overflow-negate-2.c	2014-04-15 11:43:33.411960330 +0200
@@ -1,7 +1,5 @@
 /* { dg-do run } */
-/* { dg-options "-fsanitize=signed-integer-overflow -Wno-unused-variable" } */
-
-#include <stdio.h>
+/* { dg-options "-fsanitize=signed-integer-overflow -Wno-unused-variable -fno-sanitize-recover" } */
 
 #define SCHAR_MIN (-__SCHAR_MAX__ - 1)
 #define SHRT_MIN (-__SHRT_MAX__ - 1)
@@ -14,8 +12,6 @@
 int
 main (void)
 {
-  fputs ("UBSAN TEST START\n", stderr);
-
   volatile signed char c = -SCHAR_MIN;
   CHECK (c, -128);
 
@@ -37,9 +33,5 @@ main (void)
   volatile long long lli = LLONG_MIN;
   lli = -(unsigned long long) lli;
   CHECK (lli, -0x8000000000000000L);
-
-  fputs ("UBSAN TEST END\n", stderr);
   return 0;
 }
-
-/* { dg-output "UBSAN TEST START(\n|\r\n|\r)UBSAN TEST END" } */
--- gcc/testsuite/c-c++-common/ubsan/vla-2.c.jj	2014-03-25 09:22:05.218131434 +0100
+++ gcc/testsuite/c-c++-common/ubsan/vla-2.c	2014-04-15 11:43:35.537949157 +0200
@@ -1,22 +1,14 @@
 /* { dg-do run } */
-/* { dg-options "-fsanitize=vla-bound -Wall -Wno-unused-variable" } */
-
-#include <stdio.h>
+/* { dg-options "-fsanitize=vla-bound -Wall -Wno-unused-variable -fno-sanitize-recover" } */
 
 int
 main (void)
 {
-  fputs ("UBSAN TEST START\n", stderr);
-
   const int t = 0;
   struct s {
     int x;
     /* Don't instrument this one.  */
     int g[t];
   };
-
-  fputs ("UBSAN TEST END\n", stderr);
   return 0;
 }
-
-/* { dg-output "UBSAN TEST START(\n|\r\n|\r)UBSAN TEST END" } */
--- gcc/testsuite/c-c++-common/ubsan/overflow-mul-1.c.jj	2014-03-25 09:22:05.226131391 +0100
+++ gcc/testsuite/c-c++-common/ubsan/overflow-mul-1.c	2014-04-15 11:43:38.674932672 +0200
@@ -1,7 +1,5 @@
 /* { dg-do run } */
-/* { dg-options "-fsanitize=signed-integer-overflow -Wno-unused-variable" } */
-
-#include <stdio.h>
+/* { dg-options "-fsanitize=signed-integer-overflow -Wno-unused-variable -fno-sanitize-recover" } */
 
 #define SCHAR_MAX __SCHAR_MAX__
 #define SHRT_MAX __SHRT_MAX__
@@ -18,8 +16,6 @@ check (int i, int j)
 int
 main (void)
 {
-  fputs ("UBSAN TEST START\n", stderr);
-
   /* Test integer promotion.  */
 #if __SCHAR_MAX__ == 127
   volatile signed char a = -2;
@@ -45,9 +41,5 @@ main (void)
   o = m * n;
   check (o, INT_MIN);
 #endif
-
-  fputs ("UBSAN TEST END\n", stderr);
   return 0;
 }
-
-/* { dg-output "UBSAN TEST START(\n|\r\n|\r)UBSAN TEST END" } */
--- gcc/testsuite/c-c++-common/ubsan/pr60613-1.c.jj	2014-03-25 09:22:05.218131434 +0100
+++ gcc/testsuite/c-c++-common/ubsan/pr60613-1.c	2014-04-15 11:43:41.800916245 +0200
@@ -1,8 +1,6 @@
 /* PR sanitizer/60613 */
 /* { dg-do run } */
-/* { dg-options "-fsanitize=undefined" } */
-
-#include <stdio.h>
+/* { dg-options "-fsanitize=undefined -fno-sanitize-recover" } */
 
 long long y;
 
@@ -26,16 +24,10 @@ bar (long long x)
 int
 main ()
 {
-  fputs ("UBSAN TEST START\n", stderr);
-
   y = 1;
   if (foo (8 - 2040) != 8 - 1)
     __builtin_abort ();
   if (bar (1) != 8 - 1)
     __builtin_abort ();
-
-  fputs ("UBSAN TEST END\n", stderr);
   return 0;
 }
-
-/* { dg-output "UBSAN TEST START(\n|\r\n|\r)UBSAN TEST END" } */
--- gcc/testsuite/c-c++-common/ubsan/shift-6.c.jj	2014-03-25 09:22:05.228131380 +0100
+++ gcc/testsuite/c-c++-common/ubsan/shift-6.c	2014-04-15 11:43:44.649901274 +0200
@@ -1,15 +1,11 @@
 /* PR sanitizer/58413 */
 /* { dg-do run { target int32plus } } */
-/* { dg-options "-fsanitize=shift -w" } */
-
-#include <stdio.h>
+/* { dg-options "-fsanitize=shift -w -fno-sanitize-recover" } */
 
 int x = 7;
 int
 main (void)
 {
-  fputs ("UBSAN TEST START\n", stderr);
-
   /* All of the following should pass.  */
   int A[128 >> 5] = {};
   int B[128 << 5] = {};
@@ -30,9 +26,5 @@ main (void)
     case 128 >> (4 + 1):
       return 1;
     }
-
-  fputs ("UBSAN TEST END\n", stderr);
   return 0;
 }
-
-/* { dg-output "UBSAN TEST START(\n|\r\n|\r)UBSAN TEST END" } */
--- gcc/testsuite/c-c++-common/ubsan/overflow-mul-3.c.jj	2014-03-25 09:22:05.226131391 +0100
+++ gcc/testsuite/c-c++-common/ubsan/overflow-mul-3.c	2014-04-15 11:43:47.150888133 +0200
@@ -1,7 +1,5 @@
 /* { dg-do run } */
-/* { dg-options "-fsanitize=signed-integer-overflow" } */
-
-#include <stdio.h>
+/* { dg-options "-fsanitize=signed-integer-overflow -fno-sanitize-recover" } */
 
 __attribute__((noinline, noclone)) long long
 mul (long long x, long long y)
@@ -31,16 +29,10 @@ long long tab[] = {
 int
 main ()
 {
-  fputs ("UBSAN TEST START\n", stderr);
-
   unsigned int i;
   for (i = 0; i < sizeof (tab) / sizeof (long long); i += 3)
     if (mul (tab[i], tab[i + 1]) != tab[i + 2]
         || mul (tab[i + 1], tab[i]) != tab[i + 2])
       __builtin_abort ();
-
-  fputs ("UBSAN TEST END\n", stderr);
   return 0;
 }
-
-/* { dg-output "UBSAN TEST START(\n|\r\n|\r)UBSAN TEST END" } */
--- gcc/testsuite/c-c++-common/ubsan/overflow-add-3.c.jj	2014-04-15 10:56:15.182674640 +0200
+++ gcc/testsuite/c-c++-common/ubsan/overflow-add-3.c	2014-04-15 10:57:44.703204633 +0200
@@ -0,0 +1,17 @@
+/* { dg-do run } */
+/* { dg-options "-fsanitize=signed-integer-overflow -Wno-unused-variable -fno-sanitize-recover" } */
+/* { dg-shouldfail "ubsan" } */
+
+#define INT_MAX __INT_MAX__
+#define INT_MIN (-__INT_MAX__ - 1)
+
+int
+main (void)
+{
+  volatile int j = INT_MAX;
+  volatile int i = 1;
+  volatile int k = j + i;
+  return 0;
+}
+
+/* { dg-output "signed integer overflow: 2147483647 \\+ 1 cannot be represented in type 'int'" } */
--- gcc/testsuite/c-c++-common/ubsan/overflow-add-4.c.jj	2014-04-15 10:58:10.268070265 +0200
+++ gcc/testsuite/c-c++-common/ubsan/overflow-add-4.c	2014-04-15 10:58:28.383975015 +0200
@@ -0,0 +1,15 @@
+/* { dg-do run } */
+/* { dg-options "-fsanitize=signed-integer-overflow -Wno-unused-variable -fsanitize-undefined-trap-on-error" } */
+/* { dg-shouldfail "ubsan" } */
+
+#define INT_MAX __INT_MAX__
+#define INT_MIN (-__INT_MAX__ - 1)
+
+int
+main (void)
+{
+  volatile int j = INT_MAX;
+  volatile int i = 1;
+  volatile int k = j + i;
+  return 0;
+}
--- gcc/testsuite/c-c++-common/ubsan/div-by-zero-6.c.jj	2014-04-15 10:36:27.241889827 +0200
+++ gcc/testsuite/c-c++-common/ubsan/div-by-zero-6.c	2014-04-15 11:44:36.665628047 +0200
@@ -0,0 +1,49 @@
+/* { dg-do run } */
+/* { dg-options "-fsanitize=integer-divide-by-zero -Wno-div-by-zero" } */
+
+#include <stdio.h>
+
+int x;
+
+__attribute__((noinline, noclone))
+void
+barrier (void)
+{
+  asm volatile ("" : : : "memory");
+  if (x)
+    __builtin_exit (1);
+}
+
+int
+main (void)
+{
+  volatile int a = 0;
+  volatile long long int b = 0;
+  volatile unsigned int c = 1;
+
+  barrier (); fputs ("1st\n", stderr); barrier ();
+  a / b;
+  barrier (); fputs ("2nd\n", stderr); barrier ();
+  0 / 0;
+  barrier (); fputs ("3rd\n", stderr); barrier ();
+  a / 0;
+  barrier (); fputs ("4th\n", stderr); barrier ();
+  0 / b;
+  barrier (); fputs ("5th\n", stderr); barrier ();
+  2 / --c;
+  barrier (); fputs ("6th\n", stderr); barrier ();
+
+  return 0;
+}
+
+/* { dg-output "1st(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*division by zero\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "2nd(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*division by zero\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "3rd(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*division by zero\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "4th(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*division by zero\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "5th(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*division by zero\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "6th" } */
--- gcc/testsuite/c-c++-common/ubsan/div-by-zero-7.c.jj	2014-04-15 10:49:23.124815653 +0200
+++ gcc/testsuite/c-c++-common/ubsan/div-by-zero-7.c	2014-04-15 11:44:45.795580108 +0200
@@ -0,0 +1,41 @@
+/* { dg-do run } */
+/* { dg-options "-fsanitize=integer-divide-by-zero -Wno-div-by-zero -fno-sanitize-recover" } */
+/* { dg-shouldfail "ubsan" } */
+
+#include <stdio.h>
+
+int x;
+
+__attribute__((noinline, noclone))
+void
+barrier (void)
+{
+  asm volatile ("" : : : "memory");
+  if (++x == 3)
+    __builtin_exit (0);
+}
+
+int
+main (void)
+{
+  volatile int a = 0;
+  volatile long long int b = 0;
+  volatile unsigned int c = 1;
+
+  barrier (); fputs ("1st\n", stderr); barrier ();
+  a / b;
+  barrier (); fputs ("2nd\n", stderr); barrier ();
+  0 / 0;
+  barrier (); fputs ("3rd\n", stderr); barrier ();
+  a / 0;
+  barrier (); fputs ("4th\n", stderr); barrier ();
+  0 / b;
+  barrier (); fputs ("5th\n", stderr); barrier ();
+  2 / --c;
+  barrier (); fputs ("6th\n", stderr); barrier ();
+
+  return 0;
+}
+
+/* { dg-output "1st(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*division by zero" } */

	Jakub

^ permalink raw reply	[flat|nested] 17+ messages in thread

end of thread, other threads:[~2014-05-15 19:27 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-04-15 10:12 [PATCH] Add support for -fno-sanitize-recover and -fsanitize-undefined-trap-on-error (PR sanitizer/60275) Jakub Jelinek
2014-04-23  8:14 ` Richard Biener
2014-05-15 10:30 ` Richard Sandiford
2014-05-15 10:34   ` Jakub Jelinek
2014-05-15 10:38     ` Marek Polacek
2014-05-15 12:42       ` Richard Sandiford
2014-05-15 12:47         ` Marek Polacek
2014-05-15 13:01           ` Richard Biener
2014-05-15 10:39     ` Ramana Radhakrishnan
2014-05-15 15:08       ` Marek Polacek
2014-05-15 15:16         ` Jakub Jelinek
2014-05-15 15:22           ` Marek Polacek
2014-05-15 18:32         ` Toon Moene
2014-05-15 18:37           ` Marek Polacek
2014-05-15 19:11             ` Jakub Jelinek
2014-05-15 19:20               ` Toon Moene
2014-05-15 19:27               ` Marek Polacek

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).