diff mbox

Add support for -fno-sanitize-recover and -fsanitize-undefined-trap-on-error (PR sanitizer/60275)

Message ID 20140415101156.GB1817@tucnak.redhat.com
State New
Headers show

Commit Message

Jakub Jelinek April 15, 2014, 10:11 a.m. UTC
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.


	Jakub

Comments

Richard Biener April 23, 2014, 8:11 a.m. UTC | #1
On Tue, 15 Apr 2014, Jakub Jelinek wrote:

> 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?

Works for me.

Thanks,
Richard.

> 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
> 
>
Richard Sandiford May 15, 2014, 10:30 a.m. UTC | #2
Jakub Jelinek <jakub@redhat.com> writes:
> 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.

Would it make sense for this to be the default for bootstrap-ubsan,
so that the bootstrap fails on undefined behaviour?

Thanks,
Richard
Jakub Jelinek May 15, 2014, 10:33 a.m. UTC | #3
On Thu, May 15, 2014 at 11:30:40AM +0100, Richard Sandiford wrote:
> Jakub Jelinek <jakub@redhat.com> writes:
> > 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.
> 
> Would it make sense for this to be the default for bootstrap-ubsan,
> so that the bootstrap fails on undefined behaviour?

Perhaps eventually, but is current bootstrap-ubsan really ubsan error free
on at least the major targets?  I've made some efforts towards that goal on
x86_64-linux, but haven't tried bootstrap-ubsan recently.

	Jakub
Marek Polacek May 15, 2014, 10:38 a.m. UTC | #4
On Thu, May 15, 2014 at 12:33:57PM +0200, Jakub Jelinek wrote:
> On Thu, May 15, 2014 at 11:30:40AM +0100, Richard Sandiford wrote:
> > Jakub Jelinek <jakub@redhat.com> writes:
> > > 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.
> > 
> > Would it make sense for this to be the default for bootstrap-ubsan,
> > so that the bootstrap fails on undefined behaviour?
> 
> Perhaps eventually, but is current bootstrap-ubsan really ubsan error free
> on at least the major targets?  I've made some efforts towards that goal on
> x86_64-linux, but haven't tried bootstrap-ubsan recently.

It's not, I'm seeing many 
/home/marek/src/gcc/gcc/wide-int.h:1734:7: runtime error: shift
exponent 64 is too large for 64-bit type 'long unsigned int'
plus I think I remember some other fails.

	Marek
Ramana Radhakrishnan May 15, 2014, 10:39 a.m. UTC | #5
On Thu, May 15, 2014 at 11:33 AM, Jakub Jelinek <jakub@redhat.com> wrote:
> On Thu, May 15, 2014 at 11:30:40AM +0100, Richard Sandiford wrote:
>> Jakub Jelinek <jakub@redhat.com> writes:
>> > 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.
>>
>> Would it make sense for this to be the default for bootstrap-ubsan,
>> so that the bootstrap fails on undefined behaviour?
>
> Perhaps eventually, but is current bootstrap-ubsan really ubsan error free
> on at least the major targets?  I've made some efforts towards that goal on
> x86_64-linux, but haven't tried bootstrap-ubsan recently.

What's the overhead with bootstrap-ubsan ?

Ramana

>
>         Jakub
Richard Sandiford May 15, 2014, 12:42 p.m. UTC | #6
Marek Polacek <polacek@redhat.com> writes:
> On Thu, May 15, 2014 at 12:33:57PM +0200, Jakub Jelinek wrote:
>> On Thu, May 15, 2014 at 11:30:40AM +0100, Richard Sandiford wrote:
>> > Jakub Jelinek <jakub@redhat.com> writes:
>> > > 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.
>> > 
>> > Would it make sense for this to be the default for bootstrap-ubsan,
>> > so that the bootstrap fails on undefined behaviour?
>> 
>> Perhaps eventually, but is current bootstrap-ubsan really ubsan error free
>> on at least the major targets?  I've made some efforts towards that goal on
>> x86_64-linux, but haven't tried bootstrap-ubsan recently.
>
> It's not, I'm seeing many 
> /home/marek/src/gcc/gcc/wide-int.h:1734:7: runtime error: shift
> exponent 64 is too large for 64-bit type 'long unsigned int'
> plus I think I remember some other fails.

Yeah, like Richard said on IRC a few days ago, this is partly due to the
zero-precision stuff.  We need to ween ubsan off void_zero_node and then
see where things stand.

Thanks,
Richard
Marek Polacek May 15, 2014, 12:47 p.m. UTC | #7
On Thu, May 15, 2014 at 01:42:20PM +0100, Richard Sandiford wrote:
> > It's not, I'm seeing many 
> > /home/marek/src/gcc/gcc/wide-int.h:1734:7: runtime error: shift
> > exponent 64 is too large for 64-bit type 'long unsigned int'
> > plus I think I remember some other fails.
> 
> Yeah, like Richard said on IRC a few days ago, this is partly due to the
> zero-precision stuff.  We need to ween ubsan off void_zero_node and then
> see where things stand.

Yeah, I don't like void_zero_node that much; I'll see if I can stamp it
out.  But note that I see many uses of void_zero_node in the C++ FE.
(ubsan uses void_zero_node only in the c-family/ subdirectory.)

	Marek
Richard Biener May 15, 2014, 12:59 p.m. UTC | #8
On Thu, 15 May 2014, Marek Polacek wrote:

> On Thu, May 15, 2014 at 01:42:20PM +0100, Richard Sandiford wrote:
> > > It's not, I'm seeing many 
> > > /home/marek/src/gcc/gcc/wide-int.h:1734:7: runtime error: shift
> > > exponent 64 is too large for 64-bit type 'long unsigned int'
> > > plus I think I remember some other fails.
> > 
> > Yeah, like Richard said on IRC a few days ago, this is partly due to the
> > zero-precision stuff.  We need to ween ubsan off void_zero_node and then
> > see where things stand.
> 
> Yeah, I don't like void_zero_node that much; I'll see if I can stamp it
> out.  But note that I see many uses of void_zero_node in the C++ FE.
> (ubsan uses void_zero_node only in the c-family/ subdirectory.)

They shouldn't survive gimplification though.  I suggest to add
a check for verify_expr to catch them and ICE if they appear in
the IL.

Richard.
Marek Polacek May 15, 2014, 3:08 p.m. UTC | #9
On Thu, May 15, 2014 at 11:39:26AM +0100, Ramana Radhakrishnan wrote:
> What's the overhead with bootstrap-ubsan ?

I timed normal bootstrap and bootstrap-ubsan on x86_64, 24 cores,
Intel(R) Xeon(R) CPU X5670  @ 2.93GHz (aka cfarm 20) and the results:

--enable-languages=all

real	35m10.419s
user	204m5.613s
sys	6m15.615s

--enable-languages=all --with-build-config=bootstrap-ubsan

real	71m39.338s
user	347m53.409s
sys	7m44.281s

	Marek
Jakub Jelinek May 15, 2014, 3:16 p.m. UTC | #10
On Thu, May 15, 2014 at 05:08:10PM +0200, Marek Polacek wrote:
> On Thu, May 15, 2014 at 11:39:26AM +0100, Ramana Radhakrishnan wrote:
> > What's the overhead with bootstrap-ubsan ?
> 
> I timed normal bootstrap and bootstrap-ubsan on x86_64, 24 cores,
> Intel(R) Xeon(R) CPU X5670  @ 2.93GHz (aka cfarm 20) and the results:
> 
> --enable-languages=all
> 
> real	35m10.419s
> user	204m5.613s
> sys	6m15.615s
> 
> --enable-languages=all --with-build-config=bootstrap-ubsan
> 
> real	71m39.338s
> user	347m53.409s
> sys	7m44.281s

Note that doesn't mean -fsanitize=undefined generated code is twice as slow
as code compiled without it, guess most of the extra overhead is actually
compile time (mostly larger cfg due to all the extra checks).

	Jakub
Marek Polacek May 15, 2014, 3:21 p.m. UTC | #11
On Thu, May 15, 2014 at 05:16:00PM +0200, Jakub Jelinek wrote:
> On Thu, May 15, 2014 at 05:08:10PM +0200, Marek Polacek wrote:
> > On Thu, May 15, 2014 at 11:39:26AM +0100, Ramana Radhakrishnan wrote:
> > > What's the overhead with bootstrap-ubsan ?
> > 
> > I timed normal bootstrap and bootstrap-ubsan on x86_64, 24 cores,
> > Intel(R) Xeon(R) CPU X5670  @ 2.93GHz (aka cfarm 20) and the results:
> > 
> > --enable-languages=all
> > 
> > real	35m10.419s
> > user	204m5.613s
> > sys	6m15.615s
> > 
> > --enable-languages=all --with-build-config=bootstrap-ubsan
> > 
> > real	71m39.338s
> > user	347m53.409s
> > sys	7m44.281s
> 
> Note that doesn't mean -fsanitize=undefined generated code is twice as slow
> as code compiled without it, guess most of the extra overhead is actually
> compile time (mostly larger cfg due to all the extra checks).

And I think the main offender will be the NULL checking with its extra bbs.  So to
alleviate the cfg size one can use -fsanitize=undefined -fno-sanitize=null - I'd
expect this to make a significant difference.  

	Marek
Toon Moene May 15, 2014, 6:32 p.m. UTC | #12
On 05/15/2014 05:08 PM, Marek Polacek wrote:

> On Thu, May 15, 2014 at 11:39:26AM +0100, Ramana Radhakrishnan wrote:
>> What's the overhead with bootstrap-ubsan ?
>
> I timed normal bootstrap and bootstrap-ubsan on x86_64, 24 cores,
> Intel(R) Xeon(R) CPU X5670  @ 2.93GHz (aka cfarm 20) and the results:
>
> --enable-languages=all
>
> real	35m10.419s
> user	204m5.613s
> sys	6m15.615s
>
> --enable-languages=all --with-build-config=bootstrap-ubsan
>
> real	71m39.338s
> user	347m53.409s
> sys	7m44.281s

And don't underestimate the *usefulness* of this - if you don't have the 
resources to do a ubsan bootstrap, download mine from last night 
(x86_64-linux-gnu): http://moene.org/~toon/gcc-tests.log.gz

[ I hope there is a way to discard color codings when writing error 
messages to a file, ugh ]

Kind regards,
Marek Polacek May 15, 2014, 6:37 p.m. UTC | #13
On Thu, May 15, 2014 at 08:32:36PM +0200, Toon Moene wrote:
> On 05/15/2014 05:08 PM, Marek Polacek wrote:
> 
> >On Thu, May 15, 2014 at 11:39:26AM +0100, Ramana Radhakrishnan wrote:
> >>What's the overhead with bootstrap-ubsan ?
> >
> >I timed normal bootstrap and bootstrap-ubsan on x86_64, 24 cores,
> >Intel(R) Xeon(R) CPU X5670  @ 2.93GHz (aka cfarm 20) and the results:
> >
> >--enable-languages=all
> >
> >real	35m10.419s
> >user	204m5.613s
> >sys	6m15.615s
> >
> >--enable-languages=all --with-build-config=bootstrap-ubsan
> >
> >real	71m39.338s
> >user	347m53.409s
> >sys	7m44.281s
> 
> And don't underestimate the *usefulness* of this - if you don't have the
> resources to do a ubsan bootstrap, download mine from last night
> (x86_64-linux-gnu): http://moene.org/~toon/gcc-tests.log.gz
> 
> [ I hope there is a way to discard color codings when writing error messages
> to a file, ugh ]

Sure, -fdiagnostics-color=auto "means to use color only when the
standard error is a terminal", or -fdiagnostics-color=never to turn it
off completely (testsuite uses the latter).

	Marek
Jakub Jelinek May 15, 2014, 7:10 p.m. UTC | #14
On Thu, May 15, 2014 at 08:37:07PM +0200, Marek Polacek wrote:
> > And don't underestimate the *usefulness* of this - if you don't have the
> > resources to do a ubsan bootstrap, download mine from last night
> > (x86_64-linux-gnu): http://moene.org/~toon/gcc-tests.log.gz
> > 
> > [ I hope there is a way to discard color codings when writing error messages
> > to a file, ugh ]
> 
> Sure, -fdiagnostics-color=auto "means to use color only when the
> standard error is a terminal", or -fdiagnostics-color=never to turn it
> off completely (testsuite uses the latter).

I guess Toon meant that there is no easy way? to get rid of the color
stuff in libsanitizer messages.

	Jakub
Toon Moene May 15, 2014, 7:19 p.m. UTC | #15
On 05/15/2014 09:10 PM, Jakub Jelinek wrote:

> On Thu, May 15, 2014 at 08:37:07PM +0200, Marek Polacek wrote:

>> Sure, -fdiagnostics-color=auto "means to use color only when the
>> standard error is a terminal", or -fdiagnostics-color=never to turn it
>> off completely (testsuite uses the latter).
>
> I guess Toon meant that there is no easy way? to get rid of the color
> stuff in libsanitizer messages.

Sure. The point is that the testsuite runs only write to a *file*, so 
why should I get color-coded error messages like this:

ESC[1m/home/toon/compilers/trunk/gcc/config/i386/i386.c:6577:60:ESC[1mESC[31m 
runtime error: ESC[1mESC[0mESC[1mload of value 32763, which is not a 
valid value for type 'x86_64_reg_class'ESC[1mESC[0m

?

It makes precise grepping needlessly hard ...

Otherwise, thanks very much for this work - definitely appreciated !
Marek Polacek May 15, 2014, 7:27 p.m. UTC | #16
On Thu, May 15, 2014 at 09:10:55PM +0200, Jakub Jelinek wrote:
> I guess Toon meant that there is no easy way? to get rid of the color
> stuff in libsanitizer messages.

Yikes.  I think there's no way yet; UBSAN_OPTIONS envvar, similar to
e.g. ASAN_OPTIONS, isn't supported yet it seems.
	Marek
diff mbox

Patch

--- 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" } */