public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* Request to merge Undefined Behavior Sanitizer in
@ 2013-07-25 15:35 Marek Polacek
  2013-07-25 15:40 ` Marek Polacek
                   ` (2 more replies)
  0 siblings, 3 replies; 34+ messages in thread
From: Marek Polacek @ 2013-07-25 15:35 UTC (permalink / raw)
  To: GCC Patches; +Cc: Jakub Jelinek, Jeff Law, Jason Merrill, Joseph S. Myers

[-- Attachment #1: Type: text/plain, Size: 1958 bytes --]

Hi!

I'd like to announce first version of the Undefined Behavior
Sanitizer, a tool I've spent this June/July hacking on.

It is an undefined behavior detector for the C family FEs
and works by creating a COMPOUND_EXPR around original expression,
for slightly more information  see my slides about ubsan:
http://people.redhat.com/mpolacek/src/ubsan2013.pdf

So far it sanitizes division-by-zeros, shifts and
__builtin_unreachable calls.  This is of course far from being
complete; I intend to write more features during this 4.9 stage.

Apart from the compiler components, ubsan needs a runtime library to
function.  We share that library with the LLVM implementation of
ubsan.  (We do the same for tsan/asan.)

The DejaGNU test harness is a part of this patch and passes with
both -m64 and -m32 (at least on my machine ;), haven't really tried e.g.
PPC or S390, where it could be interesting to try -m31).
I'm not aware of any major issues right now (doesn't mean there aren't
any...), but e.g. how well this works with constexpr is still subject
to discover.

Furthermore, this patch tweaks parsing of -fsanitize= option,
now it is possible to write e.g.
-fsanitize=undefined,address -fno-sanitize=shifts
.  For this, the gcc spec language has been tweaked slightly.

The ChangeLog.ubsan files are meant to disappear at commit
time, as theirs content will be updated and prepended to
the normal ChangeLog files.

I'm attaching the .tar.bz2 archive, which contains the whole patch
together with the ubsan library (located in libsanitizer/).  Everything's
also available on my git only branch ubsan.  I'll also send a patch
that contains everything but libsanitizer/ changes to make
the reviewing hopefully more convenient.

After the merge, we shouldn't forget to update the 
http://gcc.gnu.org/gcc-4.9/changes.html page.

Here I'd like to thank Jakub, without him there would be no ubsan at
all.

Regtested/bootstrapped on x86_64-linux.

Comments?

	Marek

[-- Attachment #2: U.tar.bz2 --]
[-- Type: application/x-bzip2, Size: 37919 bytes --]

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

* Re: Request to merge Undefined Behavior Sanitizer in
  2013-07-25 15:35 Request to merge Undefined Behavior Sanitizer in Marek Polacek
@ 2013-07-25 15:40 ` Marek Polacek
  2013-07-25 22:47   ` Joseph S. Myers
  2013-07-25 20:23 ` Jason Merrill
  2013-07-25 22:43 ` Request to merge Undefined Behavior Sanitizer in Joseph S. Myers
  2 siblings, 1 reply; 34+ messages in thread
From: Marek Polacek @ 2013-07-25 15:40 UTC (permalink / raw)
  To: GCC Patches; +Cc: Jakub Jelinek, Jeff Law, Jason Merrill, Joseph S. Myers

On Thu, Jul 25, 2013 at 05:32:27PM +0200, Marek Polacek wrote:
> I'm attaching the .tar.bz2 archive, which contains the whole patch
> together with the ubsan library (located in libsanitizer/).  Everything's
> also available on my git only branch ubsan.  I'll also send a patch
> that contains everything but libsanitizer/ changes to make
> the reviewing hopefully more convenient.

Here it is.

diff --git a/gcc/ChangeLog.ubsan b/gcc/ChangeLog.ubsan
new file mode 100644
index 0000000..3d15c19
--- /dev/null
+++ b/gcc/ChangeLog.ubsan
@@ -0,0 +1,117 @@
+2013-07-24  Marek Polacek  <polacek@redhat.com>
+
+	* ubsan.c (struct ubsan_typedesc): Improve comment.
+
+2013-07-21  Marek Polacek  <polacek@redhat.com>
+
+	* ubsan.c (struct ubsan_typedesc): Add comments.
+	(ubsan_typedesc_hasher::hash): Don't hash the VAR_DECL element.
+	(ubsan_typedesc_hasher::equal): Adjust comment.
+	(ubsan_typedesc_get_alloc_pool): Remove comment.
+	(empty_ubsan_typedesc_hash_table): Remove function.
+	(ubsan_source_location_type): Remove bogus comment.
+	(get_tinfo_for_type): Remove function.
+	(get_ubsan_type_info_for_type): New function.
+	(ubsan_type_descriptor): Use ASM_GENERATE_INTERNAL_LABEL instead of
+	ASM_FORMAT_PRIVATE_NAME.  Use TYPE_MAIN_VARIANT of the type.
+	(ubsan_create_data): Likewise.
+
+2013-07-15  Marek Polacek  <polacek@redhat.com>
+
+	* gcc.c (ADD_STATIC_LIBUBSAN_LIBS): Define.
+	(LIBUBSAN_SPEC): Likewise.
+	(LIBUBSAN_EARLY_SPEC): Likewise.
+	(SANITIZER_SPEC): Handle libubsan.
+	(SANITIZER_EARLY_SPEC): Likewise.
+
+2013-07-15  Marek Polacek  <polacek@redhat.com>
+
+	* builtin-attrs.def (ATTR_COLD_NOTHROW_LEAF_LIST): Define.
+	* sanitizer.def (BUILT_IN_UBSAN_HANDLE_DIVREM_OVERFLOW): Don't mark
+	as NORETURN.
+	(BUILT_IN_UBSAN_HANDLE_SHIFT_OUT_OF_BOUNDS): Likewise.
+	* asan.c (ATTR_COLD_NOTHROW_LEAF_LIST): Define.
+
+2013-07-14  Marek Polacek  <polacek@redhat.com>
+
+	* opts.c (common_handle_option): Add -fsanitize=unreachable option.
+	* builtins.c (fold_builtin_0): Use SANITIZE_UNREACHABLE instead of
+	SANITIZE_UNDEFINED.
+	* flag-types.h (enum sanitize_code): Add SANITIZE_UNREACHABLE.
+
+2013-07-14  Marek Polacek  <polacek@redhat.com>
+
+	* Makefile.in (c-family/c-ubsan.o): Add alloc-pool.h, CGRAPH_H,
+	GIMPLE_H, HASH_TABLE_H, output.h, toplev.h and ubsan.h dependencies.
+	(builtins.o): Add ubsan.h dependency.
+
+2013-07-14  Marek Polacek  <polacek@redhat.com>
+
+	* builtins.c: Include ubsan.h.
+	(fold_builtin_0): Instrument __builtin_unreachable.
+	* sanitizer.def (BUILT_IN_UBSAN_HANDLE_BUILTIN_UNREACHABLE): Define.
+	* Makefile.in: Add ubsan.c.
+	* ubsan.h: New file.
+	* ubsan.c: New file.
+
+2013-07-14  Jakub Jelinek  <jakub@redhat.com>
+
+	* gcc.c: Document %{%:function(args):X}.
+	(SANITIZER_EARLY_SPEC, SANITIZER_SPEC): Use %:sanitize(address)
+	instead of fsanitize=address and %:sanitize(thread) instead of
+	fsanitize=thread.
+	(static_spec_functions): Add sanitize.
+	(handle_spec_function): Add retval_nonnull argument and if non-NULL,
+	store funcval != NULL there.
+	(do_spec_1): Adjust handle_spec_function caller.
+	(handle_braces): Allow %:function(args) as condition.
+	(sanitize_spec_function): New function.
+	* common.opt (fsanitize=): Add Driver.
+	* config/darwin.h (LINK_COMMAND_SPEC_A): Use %:sanitize(address)
+	instead of fsanitize=address.
+	* config/arm/linux-eabi.h (ASAN_CC1_SPEC): Use %:sanitize(address)
+	instead of fsanitize=address*.
+
+2013-07-14  Marek Polacek  <polacek@redhat.com>
+
+	* common.opt (flag_sanitize): Add variable.
+	(fsanitize=): Add option.
+	(fsanitize=thread): Remove option.
+	(fsanitize=address): Likewise.
+	* flag-types.h (sanitize_code): New enum.
+	* opts.c (common_handle_option): Parse command line arguments
+	of -fsanitize=.
+	* varasm.c (get_variable_section): Adjust.
+	(assemble_noswitch_variable): Likewise.
+	(assemble_variable): Likewise.
+	(output_constant_def_contents): Likewise.
+	(categorize_decl_for_section): Likewise.
+	(place_block_symbol): Likewise.
+	(output_object_block): Likewise.
+	* builtins.def: Likewise.
+	* toplev.c (compile_file): Likewise.
+	(process_options): Likewise.
+	* cppbuiltin.c: Likewise.
+	* tsan.c (tsan_pass): Likewise.
+	(tsan_gate): Likewise.
+	(tsan_gate_O0): Likewise.
+	* cfgexpand.c (partition_stack_vars): Likewise.
+	(expand_stack_vars): Likewise.
+	(defer_stack_allocation): Likewise.
+	(expand_used_vars): Likewise.
+	* cfgcleanup.c (old_insns_match_p): Likewise.
+	* asan.c (asan_finish_file): Likewise.
+	(asan_instrument): Likewise.
+	(gate_asan): Likewise.
+
+2013-07-05  Marek Polacek  <polacek@redhat.com>
+
+	* Makefile.in: Add ubsan.c.
+	* common.opt: Add -fsanitize=undefined option.
+	* doc/invoke.texi: Document the new flag.
+	* sanitizer.def (DEF_SANITIZER_BUILTIN): Define.
+	* builtin-attrs.def (ATTR_COLD): Define.
+	* asan.c (initialize_sanitizer_builtins): Build
+	BT_FN_VOID_PTR_PTR_PTR.
+	* builtins.def (BUILT_IN_UBSAN_HANDLE_DIVREM_OVERFLOW,
+	BUILT_IN_UBSAN_HANDLE_SHIFT_OUT_OF_BOUNDS): Define.
diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index fb0cb4b..f016f7f 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1153,7 +1153,7 @@ C_COMMON_OBJS = c-family/c-common.o c-family/c-cppbuiltin.o c-family/c-dump.o \
   c-family/c-omp.o c-family/c-opts.o c-family/c-pch.o \
   c-family/c-ppoutput.o c-family/c-pragma.o c-family/c-pretty-print.o \
   c-family/c-semantics.o c-family/c-ada-spec.o tree-mudflap.o \
-  c-family/array-notation-common.o
+  c-family/array-notation-common.o c-family/c-ubsan.o
 
 # Language-independent object files.
 # We put the insn-*.o files first so that a parallel make will build
@@ -1381,6 +1381,7 @@ OBJS = \
 	tree-affine.o \
 	asan.o \
 	tsan.o \
+	ubsan.o \
 	tree-call-cdce.o \
 	tree-cfg.o \
 	tree-cfgcleanup.o \
@@ -2025,6 +2026,10 @@ c-family/array-notation-common.o : c-family/array-notation-common.c $(TREE_H) \
 c-family/stub-objc.o : c-family/stub-objc.c $(CONFIG_H) $(SYSTEM_H) \
 	coretypes.h $(TREE_H) $(C_COMMON_H) c-family/c-objc.h
 
+c-family/c-ubsan.o : c-family/c-ubsan.c $(CONFIG_H) $(SYSTEM_H) \
+	coretypes.h $(TREE_H) $(C_COMMON_H) c-family/c-ubsan.h \
+	alloc-pool.h $(CGRAPH_H) $(GIMPLE_H) $(HASH_TABLE_H) output.h \
+	toplev.h ubsan.h
 default-c.o: config/default-c.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
   $(C_TARGET_H) $(C_TARGET_DEF_H)
 	$(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) \
@@ -2261,8 +2266,11 @@ tsan.o : $(CONFIG_H) $(SYSTEM_H) $(TREE_H) $(TREE_INLINE_H) \
    $(TM_H) coretypes.h $(TREE_DUMP_H) $(TREE_PASS_H) $(CGRAPH_H) $(GGC_H) \
    $(BASIC_BLOCK_H) $(FLAGS_H) $(FUNCTION_H) \
    $(TM_P_H) $(TREE_FLOW_H) $(DIAGNOSTIC_CORE_H) $(GIMPLE_H) tree-iterator.h \
-   intl.h cfghooks.h output.h options.h c-family/c-common.h tsan.h asan.h \
+   intl.h cfghooks.h output.h options.h $(C_COMMON_H) tsan.h asan.h \
    tree-ssa-propagate.h
+ubsan.o : ubsan.c ubsan.h $(CONFIG_H) $(SYSTEM_H) $(GIMPLE_H) \
+   output.h coretypes.h $(TREE_H) alloc-pool.h $(CGRAPH_H) $(HASH_TABLE_H) \
+   toplev.h $(C_COMMON_H)
 tree-ssa-tail-merge.o: tree-ssa-tail-merge.c \
    $(SYSTEM_H) $(CONFIG_H) coretypes.h $(TM_H) $(BITMAP_H) \
    $(FLAGS_H) $(TM_P_H) $(BASIC_BLOCK_H) $(CFGLOOP_H) \
@@ -2820,7 +2828,7 @@ builtins.o : builtins.c builtins.h $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
    hard-reg-set.h $(DIAGNOSTIC_CORE_H) hard-reg-set.h $(EXCEPT_H) \
    $(TM_P_H) $(PREDICT_H) $(LIBFUNCS_H) langhooks.h $(BASIC_BLOCK_H) \
    tree-mudflap.h realmpfr.h $(BUILTINS_DEF) $(MACHMODE_H) \
-   $(DIAGNOSTIC_CORE_H) $(TREE_FLOW_H) value-prof.h
+   $(DIAGNOSTIC_CORE_H) $(TREE_FLOW_H) value-prof.h ubsan.h
 calls.o : calls.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
    $(TREE_H) $(FLAGS_H) $(EXPR_H) $(OPTABS_H) langhooks.h $(TARGET_H) \
    $(LIBFUNCS_H) $(REGS_H) $(DIAGNOSTIC_CORE_H) output.h \
@@ -3810,6 +3818,7 @@ GTFILES = $(CPP_ID_DATA_H) $(srcdir)/input.h $(srcdir)/coretypes.h \
   $(srcdir)/ipa-inline.h \
   $(srcdir)/asan.c \
   $(srcdir)/tsan.c \
+  $(srcdir)/ubsan.c \
   @all_gtfiles@
 
 # Compute the list of GT header files from the corresponding C sources,
diff --git a/gcc/asan.c b/gcc/asan.c
index b12cf44..7d8c4a5 100644
--- a/gcc/asan.c
+++ b/gcc/asan.c
@@ -2034,6 +2034,9 @@ initialize_sanitizer_builtins (void)
   tree BT_FN_VOID = build_function_type_list (void_type_node, NULL_TREE);
   tree BT_FN_VOID_PTR
     = build_function_type_list (void_type_node, ptr_type_node, NULL_TREE);
+  tree BT_FN_VOID_PTR_PTR_PTR
+    = build_function_type_list (void_type_node, ptr_type_node,
+				ptr_type_node, ptr_type_node, NULL_TREE);
   tree BT_FN_VOID_PTR_PTRMODE
     = build_function_type_list (void_type_node, ptr_type_node,
 				build_nonstandard_integer_type (POINTER_SIZE,
@@ -2099,6 +2102,12 @@ initialize_sanitizer_builtins (void)
 #undef ATTR_TMPURE_NORETURN_NOTHROW_LEAF_LIST
 #define ATTR_TMPURE_NORETURN_NOTHROW_LEAF_LIST \
   ECF_TM_PURE | ATTR_NORETURN_NOTHROW_LEAF_LIST
+#undef ATTR_COLD_NOTHROW_LEAF_LIST
+#define ATTR_COLD_NOTHROW_LEAF_LIST \
+  /* ECF_COLD missing */ ATTR_NOTHROW_LEAF_LIST
+#undef ATTR_COLD_NORETURN_NOTHROW_LEAF_LIST
+#define ATTR_COLD_NORETURN_NOTHROW_LEAF_LIST \
+  /* ECF_COLD missing */ ATTR_NORETURN_NOTHROW_LEAF_LIST
 #undef DEF_SANITIZER_BUILTIN
 #define DEF_SANITIZER_BUILTIN(ENUM, NAME, TYPE, ATTRS) \
   decl = add_builtin_function ("__builtin_" NAME, TYPE, ENUM,		\
@@ -2175,7 +2184,7 @@ asan_finish_file (void)
   /* Avoid instrumenting code in the asan ctors/dtors.
      We don't need to insert padding after the description strings,
      nor after .LASAN* array.  */
-  flag_asan = 0;
+  flag_sanitize &= ~SANITIZE_ADDRESS;
 
   tree fn = builtin_decl_implicit (BUILT_IN_ASAN_INIT);
   append_to_statement_list (build_call_expr (fn, 0), &asan_ctor_statements);
@@ -2232,7 +2241,7 @@ asan_finish_file (void)
     }
   cgraph_build_static_cdtor ('I', asan_ctor_statements,
 			     MAX_RESERVED_INIT_PRIORITY - 1);
-  flag_asan = 1;
+  flag_sanitize |= SANITIZE_ADDRESS;
 }
 
 /* Instrument the current function.  */
@@ -2249,7 +2258,7 @@ asan_instrument (void)
 static bool
 gate_asan (void)
 {
-  return flag_asan != 0
+  return (flag_sanitize & SANITIZE_ADDRESS) != 0
 	  && !lookup_attribute ("no_sanitize_address",
 				DECL_ATTRIBUTES (current_function_decl));
 }
diff --git a/gcc/builtin-attrs.def b/gcc/builtin-attrs.def
index dcaeee9..7939727 100644
--- a/gcc/builtin-attrs.def
+++ b/gcc/builtin-attrs.def
@@ -83,6 +83,7 @@ DEF_LIST_INT_INT (5,6)
 #undef DEF_LIST_INT_INT
 
 /* Construct trees for identifiers.  */
+DEF_ATTR_IDENT (ATTR_COLD, "cold")
 DEF_ATTR_IDENT (ATTR_CONST, "const")
 DEF_ATTR_IDENT (ATTR_FORMAT, "format")
 DEF_ATTR_IDENT (ATTR_FORMAT_ARG, "format_arg")
@@ -130,6 +131,10 @@ DEF_ATTR_TREE_LIST (ATTR_NORETURN_NOTHROW_LIST, ATTR_NORETURN,	\
 			ATTR_NULL, ATTR_NOTHROW_LIST)
 DEF_ATTR_TREE_LIST (ATTR_NORETURN_NOTHROW_LEAF_LIST, ATTR_NORETURN,\
 			ATTR_NULL, ATTR_NOTHROW_LEAF_LIST)
+DEF_ATTR_TREE_LIST (ATTR_COLD_NOTHROW_LEAF_LIST, ATTR_COLD,\
+			ATTR_NULL, ATTR_NOTHROW_LEAF_LIST)
+DEF_ATTR_TREE_LIST (ATTR_COLD_NORETURN_NOTHROW_LEAF_LIST, ATTR_COLD,\
+			ATTR_NULL, ATTR_NORETURN_NOTHROW_LEAF_LIST)
 DEF_ATTR_TREE_LIST (ATTR_CONST_NORETURN_NOTHROW_LEAF_LIST, ATTR_CONST,\
 			ATTR_NULL, ATTR_NORETURN_NOTHROW_LEAF_LIST)
 DEF_ATTR_TREE_LIST (ATTR_MALLOC_NOTHROW_LIST, ATTR_MALLOC,	\
diff --git a/gcc/builtins.c b/gcc/builtins.c
index 78b0d84..ad7a0c9 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -48,6 +48,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "value-prof.h"
 #include "diagnostic-core.h"
 #include "builtins.h"
+#include "ubsan.h"
 
 
 #ifndef PAD_VARARGS_DOWN
@@ -10277,6 +10278,11 @@ fold_builtin_0 (location_t loc, tree fndecl, bool ignore ATTRIBUTE_UNUSED)
     case BUILT_IN_CLASSIFY_TYPE:
       return fold_builtin_classify_type (NULL_TREE);
 
+    case BUILT_IN_UNREACHABLE:
+      if (flag_sanitize & SANITIZE_UNREACHABLE)
+	return ubsan_instrument_unreachable (loc);
+      break;
+
     default:
       break;
     }
diff --git a/gcc/builtins.def b/gcc/builtins.def
index 9b55b1f..31bca99 100644
--- a/gcc/builtins.def
+++ b/gcc/builtins.def
@@ -155,7 +155,8 @@ along with GCC; see the file COPYING3.  If not see
 #define DEF_SANITIZER_BUILTIN(ENUM, NAME, TYPE, ATTRS) \
   DEF_BUILTIN (ENUM, "__builtin_" NAME, BUILT_IN_NORMAL, TYPE, TYPE,    \
 	       true, true, true, ATTRS, true, \
-	       (flag_asan || flag_tsan))
+	      (flag_sanitize & (SANITIZE_ADDRESS | SANITIZE_THREAD \
+				| SANITIZE_UNDEFINED)))
 
 #undef DEF_CILKPLUS_BUILTIN
 #define DEF_CILKPLUS_BUILTIN(ENUM, NAME, TYPE, ATTRS)  \
diff --git a/gcc/c-family/ChangeLog.ubsan b/gcc/c-family/ChangeLog.ubsan
new file mode 100644
index 0000000..d982089
--- /dev/null
+++ b/gcc/c-family/ChangeLog.ubsan
@@ -0,0 +1,52 @@
+2013-07-14  Marek Polacek  <polacek@redhat.com>
+
+	* c-ubsan.c (struct ubsan_typedesc): Move to ubsan.c.
+	(struct ubsan_typedesc_hasher): Likewise.
+	(ubsan_typedesc_hasher::hash): Likewise.
+	(ubsan_typedesc_hasher::equal): Likewise.
+	(ubsan_typedesc_init): Likewise.
+	(ubsan_typedesc_get_alloc_pool): Likewise.
+	(get_typedesc_hash_table): Likewise.
+	(ubsan_typedesc_new): Likewise.
+	(empty_ubsan_typedesc_hash_table): Likewise.
+	(uptr_type): Likewise.
+	(ubsan_encode_value): Likewise.
+	(ubsan_type_descriptor_type): Likewise.
+	(ubsan_source_location_type): Likewise.
+	(ubsan_source_location): Likewise.
+	(get_tinfo_for_type): Likewise.
+	(ubsan_type_descriptor): Likewise.
+	(ubsan_create_data): Likewise.
+	* c-ubsan.h: Rename GCC_UBSAN_H to GCC_C_UBSAN_H.
+
+2013-07-07  Marek Polacek  <polacek@redhat.com>
+
+	* c-ubsan.c (empty_ubsan_typedesc_hash_table): Comment out function.
+
+2013-07-05  Marek Polacek  <polacek@redhat.com>
+
+	* c-ubsan.c (struct ubsan_typedesc): Declare.
+	(ubsan_typedesc_ht): New hashtable.
+	(ubsan_typedesc_hasher::hash): New function.
+	(ubsan_typedesc_hasher::equal): Likewise.
+	(ubsan_typedesc_init): Likewise.
+	(ubsan_typedesc_get_alloc_pool): Likewise.
+	(get_typedesc_hash_table): Likewise.
+	(ubsan_typedesc_new): Likewise.
+	(empty_ubsan_typedesc_hash_table): Likewise.
+	(uptr_type): Likewise.
+	(ubsan_encode_value): Likewise.
+	(ubsan_type_descriptor_type): Likewise.
+	(ubsan_source_location_type): Likewise.
+	(ubsan_source_location): Likewise.
+	(get_tinfo_for_type): Likewise.
+	(ubsan_type_descriptor): Likewise.
+	(ubsan_create_data): Likewise.
+	(ubsan_instrument_division): Create and pass arguments for the ubsan
+	library.
+	(ubsan_instrument_shift): Likewise.
+
+2013-07-05  Marek Polacek  <polacek@redhat.com>
+
+	* c-ubsan.c: New file.
+	* c-ubsan.h: New file.
diff --git a/gcc/c-family/c-ubsan.c b/gcc/c-family/c-ubsan.c
new file mode 100644
index 0000000..0c737f3
--- /dev/null
+++ b/gcc/c-family/c-ubsan.c
@@ -0,0 +1,148 @@
+/* UndefinedBehaviorSanitizer, undefined behavior detector.
+   Copyright (C) 2013 Free Software Foundation, Inc.
+   Contributed by Marek Polacek <polacek@redhat.com>
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tree.h"
+#include "alloc-pool.h"
+#include "cgraph.h"
+#include "gimple.h"
+#include "hash-table.h"
+#include "output.h"
+#include "toplev.h"
+#include "ubsan.h"
+#include "c-family/c-common.h"
+#include "c-family/c-ubsan.h"
+
+/* Instrument division by zero and INT_MIN / -1.  If not instrumenting,
+   return NULL_TREE.  */
+
+tree
+ubsan_instrument_division (location_t loc, tree op0, tree op1)
+{
+  tree t, tt;
+  tree type = TREE_TYPE (op0);
+
+  /* At this point both operands should have the same type,
+     because they are already converted to RESULT_TYPE.  */
+  gcc_assert (type == TREE_TYPE (op1));
+
+  /* TODO: REAL_TYPE is not supported yet.  */
+  if (TREE_CODE (type) != INTEGER_TYPE)
+    return NULL_TREE;
+
+  /* If we *know* that the divisor is not -1 or 0, we don't have to
+     instrument this expression.
+     ??? We could use decl_constant_value to cover up more cases.  */
+  if (TREE_CODE (op1) == INTEGER_CST
+      && integer_nonzerop (op1)
+      && !integer_minus_onep (op1))
+    return NULL_TREE;
+
+  t = fold_build2 (EQ_EXPR, boolean_type_node,
+		    op1, build_int_cst (type, 0));
+
+  /* We check INT_MIN / -1 only for signed types.  */
+  if (!TYPE_UNSIGNED (type))
+    {
+      tree x;
+      tt = fold_build2 (EQ_EXPR, boolean_type_node, op1,
+			build_int_cst (type, -1));
+      x = fold_build2 (EQ_EXPR, boolean_type_node, op0,
+		       TYPE_MIN_VALUE (type));
+      x = fold_build2 (TRUTH_AND_EXPR, boolean_type_node, x, tt);
+      t = fold_build2 (TRUTH_OR_EXPR, boolean_type_node, t, x);
+    }
+  tree data = ubsan_create_data ("__ubsan_overflow_data",
+				 loc, ubsan_type_descriptor (type),
+				 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));
+  t = fold_build3 (COND_EXPR, void_type_node, t, tt, void_zero_node);
+
+  return t;
+}
+
+/* Instrument left and right shifts.  If not instrumenting, return
+   NULL_TREE.  */
+
+tree
+ubsan_instrument_shift (location_t loc, enum tree_code code,
+			tree op0, tree op1)
+{
+  tree t, tt = NULL_TREE;
+  tree type0 = TREE_TYPE (op0);
+  tree type1 = TREE_TYPE (op1);
+  tree op1_utype = unsigned_type_for (type1);
+  HOST_WIDE_INT op0_prec = TYPE_PRECISION (type0);
+  tree uprecm1 = build_int_cst (op1_utype, op0_prec - 1);
+  tree precm1 = build_int_cst (type1, op0_prec - 1);
+
+  t = fold_convert_loc (loc, op1_utype, op1);
+  t = fold_build2 (GT_EXPR, boolean_type_node, t, uprecm1);
+
+  /* For signed x << y, in C99/C11, the following:
+     (unsigned) x >> (precm1 - y)
+     if non-zero, is undefined.  */
+  if (code == LSHIFT_EXPR
+      && !TYPE_UNSIGNED (type0)
+      && flag_isoc99)
+    {
+      tree x = fold_build2 (MINUS_EXPR, integer_type_node, precm1, op1);
+      tt = fold_convert_loc (loc, unsigned_type_for (type0), op0);
+      tt = fold_build2 (RSHIFT_EXPR, TREE_TYPE (tt), tt, x);
+      tt = fold_build2 (NE_EXPR, boolean_type_node, tt,
+			build_int_cst (TREE_TYPE (tt), 0));
+    }
+
+  /* For signed x << y, in C++11/C++14, the following:
+     x < 0 || ((unsigned) x >> (precm1 - y))
+     if > 1, is undefined.  */
+  if (code == LSHIFT_EXPR
+      && !TYPE_UNSIGNED (TREE_TYPE (op0))
+      && (cxx_dialect == cxx11 || cxx_dialect == cxx1y))
+    {
+      tree x = fold_build2 (MINUS_EXPR, integer_type_node, precm1, op1);
+      tt = fold_convert_loc (loc, unsigned_type_for (type0), op0);
+      tt = fold_build2 (RSHIFT_EXPR, TREE_TYPE (tt), tt, x);
+      tt = fold_build2 (GT_EXPR, boolean_type_node, tt,
+			build_int_cst (TREE_TYPE (tt), 1));
+      x = fold_build2 (LT_EXPR, boolean_type_node, op0,
+		       build_int_cst (type0, 0));
+      tt = fold_build2 (TRUTH_OR_EXPR, boolean_type_node, x, tt);
+    }
+  tree data = ubsan_create_data ("__ubsan_shift_data",
+				 loc, ubsan_type_descriptor (type0),
+				 ubsan_type_descriptor (type1), 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));
+  t = fold_build3 (COND_EXPR, void_type_node, t, tt, void_zero_node);
+
+  return t;
+}
diff --git a/gcc/c-family/c-ubsan.h b/gcc/c-family/c-ubsan.h
new file mode 100644
index 0000000..b032b70
--- /dev/null
+++ b/gcc/c-family/c-ubsan.h
@@ -0,0 +1,27 @@
+/* UndefinedBehaviorSanitizer, undefined behavior detector.
+   Copyright (C) 2013 Free Software Foundation, Inc.
+   Contributed by Marek Polacek <polacek@redhat.com>
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#ifndef GCC_C_UBSAN_H
+#define GCC_C_UBSAN_H
+
+extern tree ubsan_instrument_division (location_t, tree, tree);
+extern tree ubsan_instrument_shift (location_t, enum tree_code, tree, tree);
+
+#endif  /* GCC_C_UBSAN_H  */
diff --git a/gcc/c/ChangeLog.ubsan b/gcc/c/ChangeLog.ubsan
new file mode 100644
index 0000000..58e931f
--- /dev/null
+++ b/gcc/c/ChangeLog.ubsan
@@ -0,0 +1,9 @@
+2013-07-21  Marek Polacek  <polacek@redhat.com>
+
+	* c-typeck.c (build_binary_op): Call c_fully_fold on both
+	SAVE_EXPRs.
+
+2013-07-05  Marek Polacek  <polacek@redhat.com>
+
+	* c-typeck.c (build_binary_op): Add division by zero and shift
+	instrumentation.
diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c
index 30871db..d0f4b0d 100644
--- a/gcc/c/c-typeck.c
+++ b/gcc/c/c-typeck.c
@@ -39,6 +39,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "gimple.h"
 #include "c-family/c-objc.h"
 #include "c-family/c-common.h"
+#include "c-family/c-ubsan.h"
 
 /* Possible cases of implicit bad conversions.  Used to select
    diagnostic messages in convert_for_assignment.  */
@@ -9532,6 +9533,15 @@ build_binary_op (location_t location, enum tree_code code,
      operands to truth-values.  */
   bool boolean_op = false;
 
+  /* Remember whether we're doing / or %.  */
+  bool doing_div_or_mod = false;
+
+  /* Remember whether we're doing << or >>.  */
+  bool doing_shift = false;
+
+  /* Tree holding instrumentation expression.  */
+  tree instrument_expr = NULL;
+
   if (location == UNKNOWN_LOCATION)
     location = input_location;
 
@@ -9733,6 +9743,7 @@ build_binary_op (location_t location, enum tree_code code,
     case FLOOR_DIV_EXPR:
     case ROUND_DIV_EXPR:
     case EXACT_DIV_EXPR:
+      doing_div_or_mod = true;
       warn_for_div_by_zero (location, op1);
 
       if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE
@@ -9780,6 +9791,7 @@ build_binary_op (location_t location, enum tree_code code,
 
     case TRUNC_MOD_EXPR:
     case FLOOR_MOD_EXPR:
+      doing_div_or_mod = true;
       warn_for_div_by_zero (location, op1);
 
       if (code0 == VECTOR_TYPE && code1 == VECTOR_TYPE
@@ -9878,6 +9890,7 @@ build_binary_op (location_t location, enum tree_code code,
       else if ((code0 == INTEGER_TYPE || code0 == FIXED_POINT_TYPE)
 	  && code1 == INTEGER_TYPE)
 	{
+	  doing_shift = true;
 	  if (TREE_CODE (op1) == INTEGER_CST)
 	    {
 	      if (tree_int_cst_sgn (op1) < 0)
@@ -9930,6 +9943,7 @@ build_binary_op (location_t location, enum tree_code code,
       else if ((code0 == INTEGER_TYPE || code0 == FIXED_POINT_TYPE)
 	  && code1 == INTEGER_TYPE)
 	{
+	  doing_shift = true;
 	  if (TREE_CODE (op1) == INTEGER_CST)
 	    {
 	      if (tree_int_cst_sgn (op1) < 0)
@@ -10474,6 +10488,19 @@ build_binary_op (location_t location, enum tree_code code,
 	return error_mark_node;
     }
 
+  if (flag_sanitize & SANITIZE_UNDEFINED)
+    {
+      /* OP0 and/or OP1 might have side-effects.  */
+      op0 = c_save_expr (op0);
+      op1 = c_save_expr (op1);
+      op0 = c_fully_fold (op0, false, NULL);
+      op1 = c_fully_fold (op1, false, NULL);
+      if (doing_div_or_mod)
+	instrument_expr = ubsan_instrument_division (location, op0, op1);
+      else if (doing_shift)
+	instrument_expr = ubsan_instrument_shift (location, code, op0, op1);
+    }
+
   /* Treat expressions in initializers specially as they can't trap.  */
   if (int_const_or_overflow)
     ret = (require_constant_value
@@ -10497,6 +10524,11 @@ build_binary_op (location_t location, enum tree_code code,
   if (semantic_result_type)
     ret = build1 (EXCESS_PRECISION_EXPR, semantic_result_type, ret);
   protected_set_expr_location (ret, location);
+
+  if ((flag_sanitize & SANITIZE_UNDEFINED) && instrument_expr != NULL)
+    ret = fold_build2 (COMPOUND_EXPR, TREE_TYPE (ret),
+		       instrument_expr, ret);
+
   return ret;
 }
 
diff --git a/gcc/cfgcleanup.c b/gcc/cfgcleanup.c
index 99e0baa..71885a9 100644
--- a/gcc/cfgcleanup.c
+++ b/gcc/cfgcleanup.c
@@ -1137,7 +1137,7 @@ old_insns_match_p (int mode ATTRIBUTE_UNUSED, rtx i1, rtx i2)
 
       /* For address sanitizer, never crossjump __asan_report_* builtins,
 	 otherwise errors might be reported on incorrect lines.  */
-      if (flag_asan)
+      if (flag_sanitize & SANITIZE_ADDRESS)
 	{
 	  rtx call = get_call_rtx_from (i1);
 	  if (call && GET_CODE (XEXP (XEXP (call, 0), 0)) == SYMBOL_REF)
diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c
index c187273..98c157a 100644
--- a/gcc/cfgexpand.c
+++ b/gcc/cfgexpand.c
@@ -764,7 +764,7 @@ partition_stack_vars (void)
 	     sizes, as the shorter vars wouldn't be adequately protected.
 	     Don't do that for "large" (unsupported) alignment objects,
 	     those aren't protected anyway.  */
-	  if (flag_asan && isize != jsize
+	  if ((flag_sanitize & SANITIZE_ADDRESS) && isize != jsize
 	      && ialign * BITS_PER_UNIT <= MAX_SUPPORTED_STACK_ALIGNMENT)
 	    break;
 
@@ -940,7 +940,7 @@ expand_stack_vars (bool (*pred) (size_t), struct stack_vars_data *data)
       alignb = stack_vars[i].alignb;
       if (alignb * BITS_PER_UNIT <= MAX_SUPPORTED_STACK_ALIGNMENT)
 	{
-	  if (flag_asan && pred)
+	  if ((flag_sanitize & SANITIZE_ADDRESS) && pred)
 	    {
 	      HOST_WIDE_INT prev_offset = frame_offset;
 	      tree repr_decl = NULL_TREE;
@@ -1110,7 +1110,7 @@ defer_stack_allocation (tree var, bool toplevel)
   /* If stack protection is enabled, *all* stack variables must be deferred,
      so that we can re-order the strings to the top of the frame.
      Similarly for Address Sanitizer.  */
-  if (flag_stack_protect || flag_asan)
+  if (flag_stack_protect || (flag_sanitize & SANITIZE_ADDRESS))
     return true;
 
   /* We handle "large" alignment via dynamic allocation.  We want to handle
@@ -1753,7 +1753,7 @@ expand_used_vars (void)
 	    expand_stack_vars (stack_protect_decl_phase_2, &data);
 	}
 
-      if (flag_asan)
+      if (flag_sanitize & SANITIZE_ADDRESS)
 	/* Phase 3, any partitions that need asan protection
 	   in addition to phase 1 and 2.  */
 	expand_stack_vars (asan_decl_phase_3, &data);
diff --git a/gcc/common.opt b/gcc/common.opt
index 4c7933e..123d593 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -207,6 +207,10 @@ unsigned int help_columns
 Variable
 bool flag_opts_finished
 
+; What the sanitizer should instrument
+Variable
+unsigned int flag_sanitize
+
 ###
 Driver
 
@@ -850,13 +854,9 @@ fargument-noalias-anything
 Common Ignore
 Does nothing. Preserved for backward compatibility.
 
-fsanitize=address
-Common Report Var(flag_asan)
-Enable AddressSanitizer, a memory error detector
-
-fsanitize=thread
-Common Report Var(flag_tsan)
-Enable ThreadSanitizer, a data race detector
+fsanitize=
+Common Driver Report Joined
+Select what to sanitize
 
 fasynchronous-unwind-tables
 Common Report Var(flag_asynchronous_unwind_tables) Optimization
diff --git a/gcc/config/arm/linux-eabi.h b/gcc/config/arm/linux-eabi.h
index cb0aad1..f14ea84 100644
--- a/gcc/config/arm/linux-eabi.h
+++ b/gcc/config/arm/linux-eabi.h
@@ -85,7 +85,7 @@
 		       LINUX_TARGET_LINK_SPEC " " ANDROID_LINK_SPEC)
 
 #undef  ASAN_CC1_SPEC
-#define ASAN_CC1_SPEC "%{fsanitize=*:-funwind-tables}"
+#define ASAN_CC1_SPEC "%{%:sanitize(address):-funwind-tables}"
 
 #undef  CC1_SPEC
 #define CC1_SPEC							\
diff --git a/gcc/config/darwin.h b/gcc/config/darwin.h
index 82a42c8..e2a8b6c 100644
--- a/gcc/config/darwin.h
+++ b/gcc/config/darwin.h
@@ -178,7 +178,7 @@ extern GTY(()) int darwin_ms_struct;
     %{L*} %(link_libgcc) %o %{fprofile-arcs|fprofile-generate*|coverage:-lgcov} \
     %{fopenmp|ftree-parallelize-loops=*: \
       %{static|static-libgcc|static-libstdc++|static-libgfortran: libgomp.a%s; : -lgomp } } \
-    %{fsanitize=address: -lasan } \
+    %{%:sanitize(address): -lasan } \
     %{fgnu-tm: \
       %{static|static-libgcc|static-libstdc++|static-libgfortran: libitm.a%s; : -litm } } \
     %{!nostdlib:%{!nodefaultlibs:\
diff --git a/gcc/cp/ChangeLog.ubsan b/gcc/cp/ChangeLog.ubsan
new file mode 100644
index 0000000..0ab2870
--- /dev/null
+++ b/gcc/cp/ChangeLog.ubsan
@@ -0,0 +1,4 @@
+2013-07-05  Marek Polacek  <polacek@redhat.com>
+
+	* typeck.c (cp_build_binary_op): Add division by zero and shift
+	instrumentation.
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index 6f33055..7790830 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -37,6 +37,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "convert.h"
 #include "c-family/c-common.h"
 #include "c-family/c-objc.h"
+#include "c-family/c-ubsan.h"
 #include "params.h"
 
 static tree pfn_from_ptrmemfunc (tree);
@@ -3882,6 +3883,7 @@ cp_build_binary_op (location_t location,
   tree final_type = 0;
 
   tree result;
+  tree orig_type = NULL;
 
   /* Nonzero if this is an operation like MIN or MAX which can
      safely be computed in short if both args are promoted shorts.
@@ -3906,6 +3908,15 @@ cp_build_binary_op (location_t location,
   op0 = orig_op0;
   op1 = orig_op1;
 
+  /* Remember whether we're doing / or %.  */
+  bool doing_div_or_mod = false;
+
+  /* Remember whether we're doing << or >>.  */
+  bool doing_shift = false;
+
+  /* Tree holding instrumentation expression.  */
+  tree instrument_expr = NULL;
+
   if (code == TRUTH_AND_EXPR || code == TRUTH_ANDIF_EXPR
       || code == TRUTH_OR_EXPR || code == TRUTH_ORIF_EXPR
       || code == TRUTH_XOR_EXPR)
@@ -4085,8 +4096,12 @@ cp_build_binary_op (location_t location,
 	{
 	  enum tree_code tcode0 = code0, tcode1 = code1;
 	  tree cop1 = fold_non_dependent_expr_sfinae (op1, tf_none);
+	  cop1 = maybe_constant_value (cop1);
 
-	  warn_for_div_by_zero (location, maybe_constant_value (cop1));
+	  if (tcode0 == INTEGER_TYPE)
+	    doing_div_or_mod = true;
+
+	  warn_for_div_by_zero (location, cop1);
 
 	  if (tcode0 == COMPLEX_TYPE || tcode0 == VECTOR_TYPE)
 	    tcode0 = TREE_CODE (TREE_TYPE (TREE_TYPE (op0)));
@@ -4124,8 +4139,11 @@ cp_build_binary_op (location_t location,
     case FLOOR_MOD_EXPR:
       {
 	tree cop1 = fold_non_dependent_expr_sfinae (op1, tf_none);
+	cop1 = maybe_constant_value (cop1);
 
-	warn_for_div_by_zero (location, maybe_constant_value (cop1));
+	if (code0 == INTEGER_TYPE)
+	  doing_div_or_mod = true;
+	warn_for_div_by_zero (location, cop1);
       }
 
       if (code0 == VECTOR_TYPE && code1 == VECTOR_TYPE
@@ -4179,6 +4197,7 @@ cp_build_binary_op (location_t location,
 	  if (TREE_CODE (const_op1) != INTEGER_CST)
 	    const_op1 = op1;
 	  result_type = type0;
+	  doing_shift = true;
 	  if (TREE_CODE (const_op1) == INTEGER_CST)
 	    {
 	      if (tree_int_cst_lt (const_op1, integer_zero_node))
@@ -4226,6 +4245,7 @@ cp_build_binary_op (location_t location,
 	  if (TREE_CODE (const_op1) != INTEGER_CST)
 	    const_op1 = op1;
 	  result_type = type0;
+	  doing_shift = true;
 	  if (TREE_CODE (const_op1) == INTEGER_CST)
 	    {
 	      if (tree_int_cst_lt (const_op1, integer_zero_node))
@@ -4795,8 +4815,9 @@ cp_build_binary_op (location_t location,
 
       if (shorten && none_complex)
 	{
+	  orig_type = result_type;
 	  final_type = result_type;
-	  result_type = shorten_binary_op (result_type, op0, op1, 
+	  result_type = shorten_binary_op (result_type, op0, op1,
 					   shorten == -1);
 	}
 
@@ -4862,6 +4883,35 @@ cp_build_binary_op (location_t location,
   if (build_type == NULL_TREE)
     build_type = result_type;
 
+  if ((flag_sanitize & SANITIZE_UNDEFINED)
+      && !processing_template_decl
+      && (doing_div_or_mod || doing_shift))
+    {
+      /* OP0 and/or OP1 might have side-effects.  */
+      op0 = cp_save_expr (op0);
+      op1 = cp_save_expr (op1);
+      op0 = maybe_constant_value (fold_non_dependent_expr_sfinae (op0,
+								  tf_none));
+      op1 = maybe_constant_value (fold_non_dependent_expr_sfinae (op1,
+								  tf_none));
+      if (doing_div_or_mod)
+	{
+	  /* For diagnostics we want to use the promoted types without
+	     shorten_binary_op.  So convert the arguments to the
+	     original result_type.  */
+	  tree cop0 = op0;
+	  tree cop1 = op1;
+	  if (orig_type != NULL && result_type != orig_type)
+	    {
+	      cop0 = cp_convert (orig_type, op0, complain);
+	      cop1 = cp_convert (orig_type, op1, complain);
+	    }
+	  instrument_expr = ubsan_instrument_division (location, cop0, cop1);
+	}
+      else if (doing_shift)
+	instrument_expr = ubsan_instrument_shift (location, code, op0, op1);
+    }
+
   result = build2 (resultcode, build_type, op0, op1);
   result = fold_if_not_in_template (result);
   if (final_type != 0)
@@ -4872,6 +4922,10 @@ cp_build_binary_op (location_t location,
       && !TREE_OVERFLOW_P (op1))
     overflow_warning (location, result);
 
+  if ((flag_sanitize & SANITIZE_UNDEFINED) && instrument_expr != NULL)
+    result = fold_build2 (COMPOUND_EXPR, TREE_TYPE (result),
+			  instrument_expr, result);
+
   return result;
 }
 
diff --git a/gcc/cppbuiltin.c b/gcc/cppbuiltin.c
index 7ce01cb..2ceccdc 100644
--- a/gcc/cppbuiltin.c
+++ b/gcc/cppbuiltin.c
@@ -90,7 +90,7 @@ define_builtin_macros_for_compilation_flags (cpp_reader *pfile)
       cpp_define_formatted (pfile, "__PIE__=%d", flag_pie);
     }
 
-  if (flag_asan)
+  if (flag_sanitize & SANITIZE_ADDRESS)
     cpp_define (pfile, "__SANITIZE_ADDRESS__");
 
   if (optimize_size)
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 4457809..3596c6c 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -5148,6 +5148,11 @@ Memory access instructions will be instrumented to detect
 data race bugs.
 See @uref{http://code.google.com/p/data-race-test/wiki/ThreadSanitizer} for more details.
 
+@item -fsanitize=undefined
+Enable UndefinedBehaviorSanitizer, a fast undefined behavior detector
+Various computations will be instrumented to detect
+undefined behavior, e.g.@: division by zero or various overflows.
+
 @item -fdump-final-insns@r{[}=@var{file}@r{]}
 @opindex fdump-final-insns
 Dump the final internal representation (RTL) to @var{file}.  If the
diff --git a/gcc/flag-types.h b/gcc/flag-types.h
index 4fc5d33..e05255c 100644
--- a/gcc/flag-types.h
+++ b/gcc/flag-types.h
@@ -191,4 +191,17 @@ enum fp_contract_mode {
   FP_CONTRACT_FAST = 2
 };
 
+/* Different instrumentation modes.  */
+enum sanitize_code {
+  /* AddressSanitizer.  */
+  SANITIZE_ADDRESS = 1 << 0,
+  /* ThreadSanitizer.  */
+  SANITIZE_THREAD = 1 << 1,
+  /* UndefinedBehaviorSanitizer.  */
+  SANITIZE_SHIFT = 1 << 2,
+  SANITIZE_DIVIDE = 1 << 3,
+  SANITIZE_UNREACHABLE = 1 << 4,
+  SANITIZE_UNDEFINED = SANITIZE_SHIFT | SANITIZE_DIVIDE | SANITIZE_UNREACHABLE
+};
+
 #endif /* ! GCC_FLAG_TYPES_H */
diff --git a/gcc/gcc.c b/gcc/gcc.c
index 6ef4e8a..f3a7e6d 100644
--- a/gcc/gcc.c
+++ b/gcc/gcc.c
@@ -215,7 +215,7 @@ static inline void process_marked_switches (void);
 static const char *process_brace_body (const char *, const char *, const char *, int, int);
 static const struct spec_function *lookup_spec_function (const char *);
 static const char *eval_spec_function (const char *, const char *);
-static const char *handle_spec_function (const char *);
+static const char *handle_spec_function (const char *, bool *);
 static char *save_string (const char *, int);
 static void set_collect_gcc_options (void);
 static int do_spec_1 (const char *, int, const char *);
@@ -253,6 +253,7 @@ static const char *convert_filename (const char *, int, int);
 static const char *getenv_spec_function (int, const char **);
 static const char *if_exists_spec_function (int, const char **);
 static const char *if_exists_else_spec_function (int, const char **);
+static const char *sanitize_spec_function (int, const char **);
 static const char *replace_outfile_spec_function (int, const char **);
 static const char *remove_outfile_spec_function (int, const char **);
 static const char *version_compare_spec_function (int, const char **);
@@ -432,6 +433,10 @@ or with constant text in a single argument.
 	  than the OR.
 	  If %* appears in X, all of the alternatives must be starred, and
 	  only the first matching alternative is substituted.
+ %{%:function(args):X}
+	  Call function named FUNCTION with args ARGS.  If the function
+	  returns non-NULL, then X is substituted, if it returns
+	  NULL, it isn't substituted.
  %{S:X;   if S was given to GCC, substitutes X;
    T:Y;   else if T was given to GCC, substitutes Y;
     :D}   else substitutes D.  There can be as many clauses as you need.
@@ -586,6 +591,28 @@ proper position among the other output files.  */
 #define LIBTSAN_EARLY_SPEC ""
 #endif
 
+#ifndef LIBUBSAN_SPEC
+#ifdef STATIC_LIBUBSAN_LIBS
+#define ADD_STATIC_LIBUBSAN_LIBS \
+  " %{static-libubsan:" STATIC_LIBUBSAN_LIBS "}"
+#else
+#define ADD_STATIC_LIBUBSAN_LIBS
+#endif
+#ifdef LIBUBSAN_EARLY_SPEC
+#define LIBUBSAN_SPEC ADD_STATIC_LIBUBSAN_LIBS
+#elif defined(HAVE_LD_STATIC_DYNAMIC)
+#define LIBUBSAN_SPEC "%{static-libubsan:" LD_STATIC_OPTION \
+		     "} -lubsan %{static-libubsan:" LD_DYNAMIC_OPTION "}" \
+		     ADD_STATIC_LIBUBSAN_LIBS
+#else
+#define LIBUBSAN_SPEC "-lubsan" ADD_STATIC_LIBUBSAN_LIBS
+#endif
+#endif
+
+#ifndef LIBUBSAN_EARLY_SPEC
+#define LIBUBSAN_EARLY_SPEC ""
+#endif
+
 /* config.h can define LIBGCC_SPEC to override how and when libgcc.a is
    included.  */
 #ifndef LIBGCC_SPEC
@@ -708,18 +735,20 @@ proper position among the other output files.  */
 /* Linker command line options for -fsanitize= early on the command line.  */
 #ifndef SANITIZER_EARLY_SPEC
 #define SANITIZER_EARLY_SPEC "\
-%{!nostdlib:%{!nodefaultlibs:%{fsanitize=address:" LIBASAN_EARLY_SPEC "} \
-    %{fsanitize=thread:" LIBTSAN_EARLY_SPEC "}}}"
+%{!nostdlib:%{!nodefaultlibs:%{%:sanitize(address):" LIBASAN_EARLY_SPEC "} \
+    %{%:sanitize(thread):" LIBTSAN_EARLY_SPEC "} \
+    %{%:sanitize(undefined):" LIBUBSAN_EARLY_SPEC "}}}"
 #endif
 
 /* Linker command line options for -fsanitize= late on the command line.  */
 #ifndef SANITIZER_SPEC
 #define SANITIZER_SPEC "\
-%{!nostdlib:%{!nodefaultlibs:%{fsanitize=address:" LIBASAN_SPEC "\
+%{!nostdlib:%{!nodefaultlibs:%{%:sanitize(address):" LIBASAN_SPEC "\
     %{static:%ecannot specify -static with -fsanitize=address}\
-    %{fsanitize=thread:%e-fsanitize=address is incompatible with -fsanitize=thread}}\
-    %{fsanitize=thread:" LIBTSAN_SPEC "\
-    %{!pie:%{!shared:%e-fsanitize=thread linking must be done with -pie or -shared}}}}}"
+    %{%:sanitize(thread):%e-fsanitize=address is incompatible with -fsanitize=thread}}\
+    %{%:sanitize(thread):" LIBTSAN_SPEC "\
+    %{!pie:%{!shared:%e-fsanitize=thread linking must be done with -pie or -shared}}}\
+    %{%:sanitize(undefined):" LIBUBSAN_SPEC "}}}"
 #endif
 
 /* -u* was put back because both BSD and SysV seem to support it.  */
@@ -1323,6 +1352,7 @@ static const struct spec_function static_spec_functions[] =
   { "getenv",                   getenv_spec_function },
   { "if-exists",		if_exists_spec_function },
   { "if-exists-else",		if_exists_else_spec_function },
+  { "sanitize",			sanitize_spec_function },
   { "replace-outfile",		replace_outfile_spec_function },
   { "remove-outfile",		remove_outfile_spec_function },
   { "version-compare",		version_compare_spec_function },
@@ -5273,7 +5303,7 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part)
 	    break;
 
 	  case ':':
-	    p = handle_spec_function (p);
+	    p = handle_spec_function (p, NULL);
 	    if (p == 0)
 	      return -1;
 	    break;
@@ -5509,10 +5539,13 @@ eval_spec_function (const char *func, const char *args)
    ARGS is processed as a spec in a separate context and split into an
    argument vector in the normal fashion.  The function returns a string
    containing a spec which we then process in the caller's context, or
-   NULL if no processing is required.  */
+   NULL if no processing is required.
+
+   If RETVAL_NONNULL is not NULL, then store a bool whether function
+   returned non-NULL.  */
 
 static const char *
-handle_spec_function (const char *p)
+handle_spec_function (const char *p, bool *retval_nonnull)
 {
   char *func, *args;
   const char *endp, *funcval;
@@ -5558,6 +5591,8 @@ handle_spec_function (const char *p)
   funcval = eval_spec_function (func, args);
   if (funcval != NULL && do_spec_1 (funcval, 0, NULL) < 0)
     p = NULL;
+  if (retval_nonnull)
+    *retval_nonnull = funcval != NULL;
 
   free (func);
   free (args);
@@ -5701,19 +5736,28 @@ handle_braces (const char *p)
 	p++, a_is_negated = true;
 
       SKIP_WHITE();
-      if (*p == '.')
-	p++, a_is_suffix = true;
-      else if (*p == ',')
-	p++, a_is_spectype = true;
-
-      atom = p;
-      while (ISIDNUM(*p) || *p == '-' || *p == '+' || *p == '='
-	     || *p == ',' || *p == '.' || *p == '@')
-	p++;
-      end_atom = p;
+      if (*p == '%' && p[1] == ':')
+	{
+	  atom = NULL;
+	  end_atom = NULL;
+	  p = handle_spec_function (p + 2, &a_matched);
+	}
+      else
+	{
+	  if (*p == '.')
+	    p++, a_is_suffix = true;
+	  else if (*p == ',')
+	    p++, a_is_spectype = true;
+
+	  atom = p;
+	  while (ISIDNUM(*p) || *p == '-' || *p == '+' || *p == '='
+		 || *p == ',' || *p == '.' || *p == '@')
+	    p++;
+	  end_atom = p;
 
-      if (*p == '*')
-	p++, a_is_starred = 1;
+	  if (*p == '*')
+	    p++, a_is_starred = 1;
+	}
 
       SKIP_WHITE();
       switch (*p)
@@ -5738,7 +5782,7 @@ handle_braces (const char *p)
 	  if (ordered_set)
 	    goto invalid;
 
-	  if (atom == end_atom)
+	  if (atom && atom == end_atom)
 	    {
 	      if (!n_way_choice || disj_matched || *p == '|'
 		  || a_is_negated || a_is_suffix || a_is_spectype
@@ -5763,7 +5807,9 @@ handle_braces (const char *p)
 		 match.  */
 	      if (!disj_matched && !n_way_matched)
 		{
-		  if (a_is_suffix)
+		  if (atom == NULL)
+		    /* a_matched is already set by handle_spec_function.  */;
+		  else if (a_is_suffix)
 		    a_matched = input_suffix_matches (atom, end_atom);
 		  else if (a_is_spectype)
 		    a_matched = input_spec_matches (atom, end_atom);
@@ -8060,6 +8106,27 @@ if_exists_else_spec_function (int argc, const char **argv)
   return argv[1];
 }
 
+/* sanitize built-in spec function.
+
+   This returns non-NULL, if sanitizing address, thread or
+   any of the undefined behavior sanitizers.  */
+
+static const char *
+sanitize_spec_function (int argc, const char **argv)
+{
+  if (argc != 1)
+    return NULL;
+
+  if (strcmp (argv[0], "address") == 0)
+    return (flag_sanitize & SANITIZE_ADDRESS) ? "" : NULL;
+  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 NULL;
+}
+
 /* replace-outfile built-in spec function.
 
    This looks for the first argument in the outfiles array's name and
diff --git a/gcc/opts.c b/gcc/opts.c
index 6856c3c..133fe0f 100644
--- a/gcc/opts.c
+++ b/gcc/opts.c
@@ -1405,6 +1405,70 @@ common_handle_option (struct gcc_options *opts,
       opts->x_exit_after_options = true;
       break;
 
+    case OPT_fsanitize_:
+      {
+	const char *p = arg;
+	while (*p != 0)
+	  {
+	    static const struct
+	    {
+	      const char *const name;
+	      unsigned int flag;
+	      size_t len;
+	    } spec[] =
+	    {
+	      { "address", SANITIZE_ADDRESS, sizeof "address" - 1 },
+	      { "thread", SANITIZE_THREAD, sizeof "thread" - 1 },
+	      { "shift", SANITIZE_SHIFT, sizeof "shift" - 1 },
+	      { "integer-divide-by-zero", SANITIZE_DIVIDE,
+		sizeof "integer-divide-by-zero" - 1 },
+	      { "undefined", SANITIZE_UNDEFINED, sizeof "undefined" - 1 },
+	      { "unreachable", SANITIZE_UNREACHABLE,
+		sizeof "unreachable" - 1 },
+	      { NULL, 0, 0 }
+	    };
+	    const char *comma;
+	    size_t len, i;
+	    bool found = false;
+
+	    comma = strchr (p, ',');
+	    if (comma == NULL)
+	      len = strlen (p);
+	    else
+	      len = comma - p;
+	    if (len == 0)
+	      {
+		p = comma + 1;
+		continue;
+	      }
+
+	    /* Check to see if the string matches an option class name.  */
+	    for (i = 0; spec[i].name != NULL; ++i)
+	      if (len == spec[i].len
+		  && memcmp (p, spec[i].name, len) == 0)
+		{
+		  /* Handle both -fsanitize and -fno-sanitize cases.  */
+		  if (value)
+		    flag_sanitize |= spec[i].flag;
+		  else
+		    flag_sanitize &= ~spec[i].flag;
+		  found = true;
+		  break;
+		}
+
+	    if (! found)
+	      warning_at (loc, 0,
+			  "unrecognized argument to -fsanitize= option: %q.*s",
+			  (int) len, p);
+
+	    if (comma == NULL)
+	      break;
+	    p = comma + 1;
+	  }
+
+	break;
+      }
+
     case OPT_O:
     case OPT_Os:
     case OPT_Ofast:
diff --git a/gcc/sanitizer.def b/gcc/sanitizer.def
index 99f87e5..4c8a037 100644
--- a/gcc/sanitizer.def
+++ b/gcc/sanitizer.def
@@ -283,3 +283,17 @@ DEF_SANITIZER_BUILTIN(BUILT_IN_TSAN_ATOMIC_THREAD_FENCE,
 DEF_SANITIZER_BUILTIN(BUILT_IN_TSAN_ATOMIC_SIGNAL_FENCE,
 		      "__tsan_atomic_signal_fence",
 		      BT_FN_VOID_INT, ATTR_NOTHROW_LEAF_LIST)
+
+/* Undefined Behavior Sanitizer */
+DEF_SANITIZER_BUILTIN(BUILT_IN_UBSAN_HANDLE_DIVREM_OVERFLOW,
+		      "__ubsan_handle_divrem_overflow",
+		      BT_FN_VOID_PTR_PTR_PTR,
+		      ATTR_COLD_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN(BUILT_IN_UBSAN_HANDLE_SHIFT_OUT_OF_BOUNDS,
+		      "__ubsan_handle_shift_out_of_bounds",
+		      BT_FN_VOID_PTR_PTR_PTR,
+		      ATTR_COLD_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN(BUILT_IN_UBSAN_HANDLE_BUILTIN_UNREACHABLE,
+		      "__ubsan_handle_builtin_unreachable",
+		      BT_FN_VOID_PTR,
+		      ATTR_COLD_NORETURN_NOTHROW_LEAF_LIST)
diff --git a/gcc/testsuite/ChangeLog.ubsan b/gcc/testsuite/ChangeLog.ubsan
new file mode 100644
index 0000000..453bd61
--- /dev/null
+++ b/gcc/testsuite/ChangeLog.ubsan
@@ -0,0 +1,29 @@
+2013-07-22  Marek Polacek  <polacek@redhat.com>
+
+	* c-c++-common/ubsan/div-by-zero-3.c: Add more testing.
+	* c-c++-common/ubsan/div-by-zero-1.c: Likewise.
+	* c-c++-common/ubsan/shift-1.c: Likewise.
+	* c-c++-common/ubsan/shift-2.c: Likewise.
+	* c-c++-common/ubsan/div-by-zero-2.c: Likewise.
+
+2013-07-18  Marek Polacek  <polacek@redhat.com>
+
+	* lib/ubsan-dg.exp: Fix a typo in comment.
+
+2013-07-15  Marek Polacek  <polacek@redhat.com>
+
+	* lib/ubsan-dg.exp: New file.
+	* g++.dg/ubsan/ubsan.exp: New file.
+	* gcc.dg/ubsan/ubsan.exp: New file.
+	* g++.dg/ubsan/cxx11-shift-1.C: New test.
+	* g++.dg/ubsan/cxx11-shift-2.C: New test.
+	* c-c++-common/ubsan/div-by-zero-3.c: New test.
+	* c-c++-common/ubsan/div-by-zero-1.c: New test.
+	* c-c++-common/ubsan/div-by-zero-4.c: New test.
+	* c-c++-common/ubsan/shift-3.c: New test.
+	* c-c++-common/ubsan/unreachable-1.c: New test.
+	* c-c++-common/ubsan/shift-1.c: New test.
+	* c-c++-common/ubsan/shift-2.c: New test.
+	* c-c++-common/ubsan/div-by-zero-2.c: New test.
+	* gcc.dg/ubsan/c99-shift-2.c: New test.
+	* gcc.dg/ubsan/c99-shift-1.c: New test.
diff --git a/gcc/testsuite/c-c++-common/ubsan/div-by-zero-1.c b/gcc/testsuite/c-c++-common/ubsan/div-by-zero-1.c
new file mode 100644
index 0000000..4e2a2b9
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/ubsan/div-by-zero-1.c
@@ -0,0 +1,24 @@
+/* { dg-do run } */
+/* { dg-options "-fsanitize=integer-divide-by-zero -Wno-div-by-zero" } */
+
+int
+main (void)
+{
+  volatile int a = 0;
+  volatile long long int b = 0;
+  volatile unsigned int c = 1;
+
+  a / b;
+  0 / 0;
+  a / 0;
+  0 / b;
+  2 / --c;
+
+  return 0;
+}
+
+/* { dg-output "division by zero(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*division by zero(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*division by zero(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*division by zero(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*division by zero(\n|\r\n|\r)" } */
diff --git a/gcc/testsuite/c-c++-common/ubsan/div-by-zero-2.c b/gcc/testsuite/c-c++-common/ubsan/div-by-zero-2.c
new file mode 100644
index 0000000..ee96738
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/ubsan/div-by-zero-2.c
@@ -0,0 +1,23 @@
+/* { dg-do run } */
+/* { dg-options "-fsanitize=integer-divide-by-zero -Wno-div-by-zero" } */
+
+int
+main (void)
+{
+  volatile const unsigned long int o = 1UL;
+  int zero = 0;
+
+  o / 0;
+  1UL / 0;
+  1UL / zero;
+  o / zero;
+  o / (++zero - 1);
+
+  return 0;
+}
+
+/* { dg-output "division by zero(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*division by zero(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*division by zero(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*division by zero(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*division by zero(\n|\r\n|\r)" } */
diff --git a/gcc/testsuite/c-c++-common/ubsan/div-by-zero-3.c b/gcc/testsuite/c-c++-common/ubsan/div-by-zero-3.c
new file mode 100644
index 0000000..719e6c9
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/ubsan/div-by-zero-3.c
@@ -0,0 +1,21 @@
+/* { dg-do run } */
+/* { dg-options "-fsanitize=integer-divide-by-zero -Wno-overflow" } */
+
+#include <limits.h>
+
+int
+main (void)
+{
+  volatile int min = INT_MIN;
+  volatile int zero = 0;
+
+  INT_MIN / -1;
+  min / -1;
+  min / (10 * zero - (2 - 1));
+
+  return 0;
+}
+
+/* { dg-output "division of -2147483648 by -1 cannot be represented in type int(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*division of -2147483648 by -1 cannot be represented in type int(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*division of -2147483648 by -1 cannot be represented in type int(\n|\r\n|\r)" } */
diff --git a/gcc/testsuite/c-c++-common/ubsan/div-by-zero-4.c b/gcc/testsuite/c-c++-common/ubsan/div-by-zero-4.c
new file mode 100644
index 0000000..295f624
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/ubsan/div-by-zero-4.c
@@ -0,0 +1,11 @@
+/* { dg-do run } */
+/* { dg-options "-fsanitize=integer-divide-by-zero -Wno-overflow" } */
+
+#include <limits.h>
+
+int
+main (void)
+{
+  /* This should not fail.  */
+  return (unsigned int) INT_MIN / -1;
+}
diff --git a/gcc/testsuite/c-c++-common/ubsan/shift-1.c b/gcc/testsuite/c-c++-common/ubsan/shift-1.c
new file mode 100644
index 0000000..48cf3cd
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/ubsan/shift-1.c
@@ -0,0 +1,31 @@
+/* { dg-do run } */
+/* { dg-options "-fsanitize=shift -w" } */
+
+typedef const unsigned long long int CULLI;
+typedef volatile int VI;
+struct s { signed long int a; };
+
+int
+main (void)
+{
+  int a = 1;
+  struct s s = { .a = 400 };
+  CULLI culli = 42;
+  VI vi = 370;
+  volatile int shiftcount = 153;
+
+  a <<= 152;
+  1 << shiftcount;
+  1 << 154;
+  culli << 524;
+  1 << vi++;
+  (long) 1 << (s.a + 2);
+
+  return 0;
+}
+/* { dg-output "shift exponent 152 is too large for \[^\n\r]*-bit type int(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*shift exponent 153 is too large for \[^\n\r]*-bit type int(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*shift exponent 154 is too large for \[^\n\r]*-bit type int(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*shift exponent 524 is too large for \[^\n\r]*-bit type long long unsigned int(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*shift exponent 370 is too large for \[^\n\r]*-bit type int(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*shift exponent 402 is too large for \[^\n\r]*-bit type long int(\n|\r\n|\r)" } */
diff --git a/gcc/testsuite/c-c++-common/ubsan/shift-2.c b/gcc/testsuite/c-c++-common/ubsan/shift-2.c
new file mode 100644
index 0000000..68a7d13
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/ubsan/shift-2.c
@@ -0,0 +1,23 @@
+/* { dg-do run } */
+/* { dg-options "-fsanitize=shift -w" } */
+
+int
+main (void)
+{
+  int a = 1;
+  volatile int b = -5;
+  long long int c = -6;
+
+  a << -3;
+  1 << -4;
+  1 << b;
+  a << c;
+  a << (b + c);
+
+  return 0;
+}
+/* { dg-output "shift exponent -3 is negative(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*shift exponent -4 is negative(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*shift exponent -5 is negative(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*shift exponent -6 is negative(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*shift exponent -11 is negative(\n|\r\n|\r)" } */
diff --git a/gcc/testsuite/c-c++-common/ubsan/shift-3.c b/gcc/testsuite/c-c++-common/ubsan/shift-3.c
new file mode 100644
index 0000000..c639d17
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/ubsan/shift-3.c
@@ -0,0 +1,11 @@
+/* { dg-do run } */
+/* { dg-options "-fsanitize=shift -w" } */
+
+int
+main (void)
+{
+  unsigned int a = 1;
+  a <<= 31;
+  a <<= 1;
+  return 0;
+}
diff --git a/gcc/testsuite/c-c++-common/ubsan/unreachable-1.c b/gcc/testsuite/c-c++-common/ubsan/unreachable-1.c
new file mode 100644
index 0000000..336240c
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/ubsan/unreachable-1.c
@@ -0,0 +1,10 @@
+/* { dg-do run } */
+/* { dg-options "-fsanitize=unreachable" } */
+/* { dg-shouldfail "ubsan" } */
+
+int
+main (void)
+{
+  __builtin_unreachable ();
+}
+ /* { dg-output "execution reached a __builtin_unreachable\\(\\) call" } */
diff --git a/gcc/testsuite/g++.dg/ubsan/cxx11-shift-1.C b/gcc/testsuite/g++.dg/ubsan/cxx11-shift-1.C
new file mode 100644
index 0000000..a5c0e33
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ubsan/cxx11-shift-1.C
@@ -0,0 +1,9 @@
+/* { dg-do run } */
+/* { dg-options "-fsanitize=shift -w -std=c++11" } */
+
+int
+main (void)
+{
+  int a = 1;
+  a <<= 31;
+}
diff --git a/gcc/testsuite/g++.dg/ubsan/cxx11-shift-2.C b/gcc/testsuite/g++.dg/ubsan/cxx11-shift-2.C
new file mode 100644
index 0000000..fbc16df
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ubsan/cxx11-shift-2.C
@@ -0,0 +1,10 @@
+/* { dg-do run } */
+/* { dg-options "-fsanitize=shift -w -std=c++11" } */
+
+int
+main (void)
+{
+  int a = -42;
+  a <<= 1;
+}
+/* { dg-output "left shift of negative value -42" } */
diff --git a/gcc/testsuite/g++.dg/ubsan/ubsan.exp b/gcc/testsuite/g++.dg/ubsan/ubsan.exp
new file mode 100644
index 0000000..b2651a3
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ubsan/ubsan.exp
@@ -0,0 +1,34 @@
+# Copyright (C) 2013 Free Software Foundation, Inc.
+#
+# This file is part of GCC.
+#
+# GCC is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# GCC is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3.  If not see
+# <http://www.gnu.org/licenses/>.
+
+# Load support procs.
+load_lib g++-dg.exp
+load_lib ubsan-dg.exp
+
+# Initialize `dg'.
+dg-init
+if [ubsan_init] {
+
+# Main loop.
+gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.C $srcdir/c-c++-common/ubsan/*.c]] ""
+
+}
+
+# All done.
+ubsan_finish
+dg-finish
diff --git a/gcc/testsuite/gcc.dg/ubsan/c99-shift-1.c b/gcc/testsuite/gcc.dg/ubsan/c99-shift-1.c
new file mode 100644
index 0000000..ff6776b
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ubsan/c99-shift-1.c
@@ -0,0 +1,10 @@
+/* { dg-do run } */
+/* { dg-options "-fsanitize=shift -w -std=c99" } */
+
+int
+main (void)
+{
+  int a = -42;
+  a << 1;
+}
+/* { dg-output "left shift of negative value -42" } */
diff --git a/gcc/testsuite/gcc.dg/ubsan/c99-shift-2.c b/gcc/testsuite/gcc.dg/ubsan/c99-shift-2.c
new file mode 100644
index 0000000..7dceb58
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ubsan/c99-shift-2.c
@@ -0,0 +1,10 @@
+/* { dg-do run } */
+/* { dg-options "-fsanitize=shift -w -std=c99" } */
+
+int
+main (void)
+{
+  int a = 1;
+  a <<= 31;
+}
+/* { dg-output "left shift of 1 by 31 places cannot be represented in type int" } */
diff --git a/gcc/testsuite/gcc.dg/ubsan/ubsan.exp b/gcc/testsuite/gcc.dg/ubsan/ubsan.exp
new file mode 100644
index 0000000..d077d1d
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ubsan/ubsan.exp
@@ -0,0 +1,36 @@
+# Copyright (C) 2013 Free Software Foundation, Inc.
+#
+# This file is part of GCC.
+#
+# GCC is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# GCC is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3.  If not see
+# <http://www.gnu.org/licenses/>.
+
+# GCC testsuite that uses the `dg.exp' driver.
+
+# Load support procs.
+load_lib gcc-dg.exp
+load_lib ubsan-dg.exp
+
+# Initialize `dg'.
+dg-init
+if [ubsan_init] {
+
+# Main loop.
+gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.c $srcdir/c-c++-common/ubsan/*.c]] ""
+
+}
+
+# All done.
+ubsan_finish
+dg-finish
diff --git a/gcc/testsuite/lib/ubsan-dg.exp b/gcc/testsuite/lib/ubsan-dg.exp
new file mode 100644
index 0000000..4ec5fdf
--- /dev/null
+++ b/gcc/testsuite/lib/ubsan-dg.exp
@@ -0,0 +1,104 @@
+# Copyright (C) 2013 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3.  If not see
+# <http://www.gnu.org/licenses/>.
+
+#
+# ubsan_link_flags -- compute library path and flags to find libubsan.
+# (originally from g++.exp)
+#
+
+proc ubsan_link_flags { paths } {
+    global srcdir
+    global ld_library_path
+    global shlib_ext
+
+    set gccpath ${paths}
+    set flags ""
+
+    set shlib_ext [get_shlib_extension]
+
+    if { $gccpath != "" } {
+      if { [file exists "${gccpath}/libsanitizer/ubsan/.libs/libubsan.a"]
+	   || [file exists "${gccpath}/libsanitizer/ubsan/.libs/libubsan.${shlib_ext}"] } {
+	  append flags " -B${gccpath}/libsanitizer/ubsan/ "
+	  append flags " -L${gccpath}/libsanitizer/ubsan/.libs"
+	  append ld_library_path ":${gccpath}/libsanitizer/ubsan/.libs"
+      }
+    } else {
+      global tool_root_dir
+
+      set libubsan [lookfor_file ${tool_root_dir} libubsan]
+      if { $libubsan != "" } {
+	  append flags "-L${libubsan} "
+	  append ld_library_path ":${libubsan}"
+      }
+    }
+
+    set_ld_library_path_env_vars
+
+    return "$flags"
+}
+
+#
+# ubsan_init -- called at the start of each subdir of tests
+#
+
+proc ubsan_init { args } {
+    global TEST_ALWAYS_FLAGS
+    global ALWAYS_CXXFLAGS
+    global TOOL_OPTIONS
+    global ubsan_saved_TEST_ALWAYS_FLAGS
+
+    set link_flags ""
+    if ![is_remote host] {
+	if [info exists TOOL_OPTIONS] {
+	    set link_flags "[ubsan_link_flags [get_multilibs ${TOOL_OPTIONS}]]"
+	} else {
+	    set link_flags "[ubsan_link_flags [get_multilibs]]"
+	}
+    }
+
+    if [info exists TEST_ALWAYS_FLAGS] {
+	set ubsan_saved_TEST_ALWAYS_FLAGS $TEST_ALWAYS_FLAGS
+    }
+    if [info exists ALWAYS_CXXFLAGS] {
+	set ALWAYS_CXXFLAGS [concat "{ldflags=$link_flags}" $ALWAYS_CXXFLAGS]
+    } else {
+	if [info exists TEST_ALWAYS_FLAGS] {
+	    set TEST_ALWAYS_FLAGS "$link_flags $TEST_ALWAYS_FLAGS"
+	} else {
+	    set TEST_ALWAYS_FLAGS "$link_flags"
+	}
+    }
+    if { $link_flags != "" } {
+	return 1
+    }
+    return 0
+}
+
+#
+# ubsan_finish -- called at the end of each subdir of tests
+#
+
+proc ubsan_finish { args } {
+    global TEST_ALWAYS_FLAGS
+    global ubsan_saved_TEST_ALWAYS_FLAGS
+
+    if [info exists ubsan_saved_TEST_ALWAYS_FLAGS] {
+	set TEST_ALWAYS_FLAGS $ubsan_saved_TEST_ALWAYS_FLAGS
+    } else {
+	unset TEST_ALWAYS_FLAGS
+    }
+}
diff --git a/gcc/toplev.c b/gcc/toplev.c
index de28a2d..6302634 100644
--- a/gcc/toplev.c
+++ b/gcc/toplev.c
@@ -572,10 +572,10 @@ compile_file (void)
 	mudflap_finish_file ();
 
       /* File-scope initialization for AddressSanitizer.  */
-      if (flag_asan)
+      if (flag_sanitize & SANITIZE_ADDRESS)
         asan_finish_file ();
 
-      if (flag_tsan)
+      if (flag_sanitize & SANITIZE_THREAD)
 	tsan_finish_file ();
 
       output_shared_constant_pool ();
@@ -1541,12 +1541,12 @@ process_options (void)
     warn_stack_protect = 0;
 
   /* Address Sanitizer needs porting to each target architecture.  */
-  if (flag_asan
+  if ((flag_sanitize & SANITIZE_ADDRESS)
       && (targetm.asan_shadow_offset == NULL
 	  || !FRAME_GROWS_DOWNWARD))
     {
       warning (0, "-fsanitize=address not supported for this target");
-      flag_asan = 0;
+      flag_sanitize &= ~SANITIZE_ADDRESS;
     }
 
   /* Enable -Werror=coverage-mismatch when -Werror and -Wno-error
diff --git a/gcc/tsan.c b/gcc/tsan.c
index d218eed..d24be19 100644
--- a/gcc/tsan.c
+++ b/gcc/tsan.c
@@ -713,7 +713,7 @@ tsan_pass (void)
 static bool
 tsan_gate (void)
 {
-  return flag_tsan != 0;
+  return (flag_sanitize & SANITIZE_THREAD) != 0;
 }
 
 /* Inserts __tsan_init () into the list of CTORs.  */
@@ -756,7 +756,7 @@ struct gimple_opt_pass pass_tsan =
 static bool
 tsan_gate_O0 (void)
 {
-  return flag_tsan != 0 && !optimize;
+  return (flag_sanitize & SANITIZE_THREAD) != 0 && !optimize;
 }
 
 struct gimple_opt_pass pass_tsan_O0 =
diff --git a/gcc/ubsan.c b/gcc/ubsan.c
new file mode 100644
index 0000000..0bd1b96
--- /dev/null
+++ b/gcc/ubsan.c
@@ -0,0 +1,465 @@
+/* UndefinedBehaviorSanitizer, undefined behavior detector.
+   Copyright (C) 2013 Free Software Foundation, Inc.
+   Contributed by Marek Polacek <polacek@redhat.com>
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tree.h"
+#include "alloc-pool.h"
+#include "cgraph.h"
+#include "gimple.h"
+#include "hash-table.h"
+#include "output.h"
+#include "toplev.h"
+#include "ubsan.h"
+#include "c-family/c-common.h"
+
+/* This type represents an entry in the hash table; this hash table
+   maps from a TYPE to a ubsan type descriptor VAR_DECL for that type.  */
+struct ubsan_typedesc
+{
+  /* This represents the type of a variable.  */
+  tree type;
+
+  /* This is the VAR_DECL of the type.  */
+  tree decl;
+};
+
+static alloc_pool ubsan_typedesc_alloc_pool;
+
+/* Hash table for type descriptors.  */
+struct ubsan_typedesc_hasher
+  : typed_noop_remove <ubsan_typedesc>
+{
+  typedef ubsan_typedesc value_type;
+  typedef ubsan_typedesc compare_type;
+
+  static inline hashval_t hash (const value_type *);
+  static inline bool equal (const value_type *, const compare_type *);
+};
+
+/* Hash a memory reference.  */
+
+inline hashval_t
+ubsan_typedesc_hasher::hash (const ubsan_typedesc *data)
+{
+  return iterative_hash_object (data->type, 0);
+}
+
+/* Compare two data types.  */
+
+inline bool
+ubsan_typedesc_hasher::equal (const ubsan_typedesc *d1,
+			      const ubsan_typedesc *d2)
+{
+  /* Here, the types should have identical __typekind,
+     __typeinfo and __typename.  */
+  return d1->type == d2->type;
+}
+
+static hash_table <ubsan_typedesc_hasher> ubsan_typedesc_ht;
+
+/* Initializes an instance of ubsan_typedesc.  */
+
+static void
+ubsan_typedesc_init (ubsan_typedesc *data, tree type, tree decl)
+{
+  data->type = type;
+  data->decl = decl;
+}
+
+/* This creates the alloc pool used to store the instances of
+   ubsan_typedesc that are stored in the hash table ubsan_typedesc_ht.  */
+
+static alloc_pool
+ubsan_typedesc_get_alloc_pool ()
+{
+  if (ubsan_typedesc_alloc_pool == NULL)
+    ubsan_typedesc_alloc_pool = create_alloc_pool ("ubsan_typedesc",
+						   sizeof (ubsan_typedesc),
+						   10);
+  return ubsan_typedesc_alloc_pool;
+}
+
+/* Returns a reference to the hash table containing data type.
+   This function ensures that the hash table is created.  */
+
+static hash_table <ubsan_typedesc_hasher> &
+get_typedesc_hash_table ()
+{
+  if (!ubsan_typedesc_ht.is_created ())
+    ubsan_typedesc_ht.create (10);
+
+  return ubsan_typedesc_ht;
+}
+
+/* Allocates memory for an instance of ubsan_typedesc into the memory
+   pool returned by ubsan_typedesc_get_alloc_pool and initialize it.
+   TYPE describes a particular type, DECL is its VAR_DECL.  */
+
+static ubsan_typedesc *
+ubsan_typedesc_new (tree type, tree decl)
+{
+  ubsan_typedesc *desc =
+    (ubsan_typedesc *) pool_alloc (ubsan_typedesc_get_alloc_pool ());
+
+  ubsan_typedesc_init (desc, type, decl);
+  return desc;
+}
+
+/* Build the ubsan uptr type.  */
+
+static tree
+uptr_type (void)
+{
+  return build_nonstandard_integer_type (POINTER_SIZE, 1);
+}
+
+/* Helper routine, which encodes a value in the uptr type.
+   Arguments with precision <= POINTER_SIZE are passed directly,
+   the rest is passed by reference.  T is a value we are to encode.  */
+
+tree
+ubsan_encode_value (tree t)
+{
+  tree type = TREE_TYPE (t);
+  switch (TREE_CODE (type))
+    {
+    case INTEGER_TYPE:
+      if (TYPE_PRECISION (type) <= POINTER_SIZE)
+	return fold_build1 (NOP_EXPR, uptr_type (), t);
+      else
+	return build_fold_addr_expr (t);
+    case REAL_TYPE:
+      {
+	unsigned int bitsize = GET_MODE_BITSIZE (TYPE_MODE (type));
+	if (bitsize <= POINTER_SIZE)
+	  {
+	    tree itype = build_nonstandard_integer_type (bitsize, true);
+	    t = fold_build1 (VIEW_CONVERT_EXPR, itype, t);
+	    return fold_convert (uptr_type (), t);
+	  }
+	else
+	  {
+	    if (!TREE_ADDRESSABLE (t))
+	      {
+		/* The reason for this is that we don't want to pessimize
+		   code by making vars unnecessarily addressable.  */
+		tree var = create_tmp_var (TREE_TYPE (t), NULL);
+		tree tem = build2 (MODIFY_EXPR, void_type_node, var, t);
+		t = build_fold_addr_expr (var);
+		return build2 (COMPOUND_EXPR, TREE_TYPE (t), tem, t);
+	      }
+	    else
+	      return build_fold_addr_expr (t);
+	  }
+      }
+    default:
+      gcc_unreachable ();
+    }
+}
+
+/* Build
+   struct __ubsan_type_descriptor
+   {
+     unsigned short __typekind;
+     unsigned short __typeinfo;
+     char __typename[];
+   }
+   type.  */
+
+static tree
+ubsan_type_descriptor_type (void)
+{
+  static const char *field_names[3]
+    = { "__typekind", "__typeinfo", "__typename" };
+  tree fields[3], ret;
+  tree itype = build_range_type (sizetype, size_zero_node, NULL_TREE);
+  tree flex_arr_type = build_array_type (char_type_node, itype);
+
+  ret = make_node (RECORD_TYPE);
+  for (int i = 0; i < 3; i++)
+    {
+      fields[i] = build_decl (UNKNOWN_LOCATION, FIELD_DECL,
+			      get_identifier (field_names[i]),
+			      (i == 2) ? flex_arr_type
+			      : short_unsigned_type_node);
+      DECL_CONTEXT (fields[i]) = ret;
+      if (i)
+	DECL_CHAIN (fields[i - 1]) = fields[i];
+    }
+  TYPE_FIELDS (ret) = fields[0];
+  TYPE_NAME (ret) = get_identifier ("__ubsan_type_descriptor");
+  layout_type (ret);
+  return ret;
+}
+
+/* Build
+   struct __ubsan_source_location
+   {
+     const char *__filename;
+     unsigned int __line;
+     unsigned int __column;
+   }
+   type.  */
+
+static tree
+ubsan_source_location_type (void)
+{
+  static const char *field_names[3]
+    = { "__filename", "__line", "__column" };
+  tree fields[3], ret;
+  tree const_char_type = char_type_node;
+  TYPE_READONLY (const_char_type) = 1;
+
+  ret = make_node (RECORD_TYPE);
+  for (int i = 0; i < 3; i++)
+    {
+      fields[i] = build_decl (UNKNOWN_LOCATION, FIELD_DECL,
+			      get_identifier (field_names[i]),
+			      (i == 0) ? build_pointer_type (const_char_type)
+			      : unsigned_type_node);
+      DECL_CONTEXT (fields[i]) = ret;
+      if (i)
+	DECL_CHAIN (fields[i - 1]) = fields[i];
+    }
+  TYPE_FIELDS (ret) = fields[0];
+  TYPE_NAME (ret) = get_identifier ("__ubsan_source_location");
+  layout_type (ret);
+  return ret;
+}
+
+/* Helper routine that returns a CONSTRUCTOR of __ubsan_source_location
+   type with its fields filled from a location_t LOC.  */
+
+static tree
+ubsan_source_location (location_t loc)
+{
+  expanded_location xloc;
+  tree type = ubsan_source_location_type ();
+  vec<constructor_elt, va_gc> *v;
+
+  xloc = expand_location (loc);
+
+  /* Fill in the values from LOC.  */
+  vec_alloc (v, 3);
+  tree ctor = build_constructor (type, v);
+  size_t len = strlen (xloc.file);
+  tree str = build_string (len + 1, xloc.file);
+  TREE_TYPE (str) = build_array_type (char_type_node,
+				      build_index_type (size_int (len)));
+  TREE_READONLY (str) = 1;
+  TREE_STATIC (str) = 1;
+  str = build_fold_addr_expr_loc (loc, str);
+  CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, str);
+  CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, build_int_cst (unsigned_type_node,
+						       xloc.line));
+  CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, build_int_cst (unsigned_type_node,
+						       xloc.column));
+  TREE_CONSTANT (ctor) = 1;
+  TREE_STATIC (ctor) = 1;
+
+  return ctor;
+}
+
+/* This routine returns a magic number for TYPE.  */
+
+static unsigned short
+get_ubsan_type_info_for_type (tree type)
+{
+  int prec = exact_log2 (TYPE_PRECISION (type));
+  if (prec == -1)
+    error ("unexpected size of type %qT", type);
+
+  return (prec << 1) | !TYPE_UNSIGNED (type);
+}
+
+/* Helper routine that returns ADDR_EXPR of a VAR_DECL of a type
+   descriptor.  It first looks into the hash table; if not found,
+   create the VAR_DECL, put it into the hash table and return the
+   ADDR_EXPR of it.  TYPE describes a particular type.  */
+
+tree
+ubsan_type_descriptor (tree type)
+{
+  hash_table <ubsan_typedesc_hasher> ht = get_typedesc_hash_table ();
+  ubsan_typedesc d;
+  ubsan_typedesc_init (&d, type, NULL);
+
+  /* See through any typedefs.  */
+  type = TYPE_MAIN_VARIANT (type);
+
+  ubsan_typedesc **slot = ht.find_slot (&d, INSERT);
+  if (*slot != NULL)
+    /* We have the VAR_DECL in the table.  Return it.  */
+    return (*slot)->decl;
+
+  tree dtype = ubsan_type_descriptor_type ();
+  vec<constructor_elt, va_gc> *v;
+  const char *tname;
+  unsigned short tkind, tinfo;
+
+  /* At least for INTEGER_TYPE/REAL_TYPE/COMPLEX_TYPE, this should work.
+     ??? For e.g. type_unsigned_for (type), the TYPE_NAME would be NULL.  */
+  if (TYPE_NAME (type) != NULL)
+    tname = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type)));
+  else
+    tname = "<unknown>";
+  if (TREE_CODE (type) == INTEGER_TYPE)
+    {
+      /* For INTEGER_TYPE, this is 0x0000.  */
+      tkind = 0x000;
+      tinfo = get_ubsan_type_info_for_type (type);
+    }
+  else if (TREE_CODE (type) == REAL_TYPE)
+    /* We don't have float support yet.  */
+    gcc_unreachable ();
+  else
+    gcc_unreachable ();
+
+  /* Create a new VAR_DECL of type descriptor.  */
+  char tmp_name[32];
+  static unsigned int type_var_id_num;
+  ASM_GENERATE_INTERNAL_LABEL (tmp_name, "Lubsan_type", type_var_id_num++);
+  tree decl = build_decl (UNKNOWN_LOCATION, VAR_DECL, get_identifier (tmp_name),
+			  dtype);
+  TREE_STATIC (decl) = 1;
+  TREE_PUBLIC (decl) = 0;
+  DECL_ARTIFICIAL (decl) = 1;
+  DECL_IGNORED_P (decl) = 1;
+  DECL_EXTERNAL (decl) = 0;
+
+  vec_alloc (v, 3);
+  tree ctor = build_constructor (dtype, v);
+  size_t len = strlen (tname);
+  tree str = build_string (len + 1, tname);
+  TREE_TYPE (str) = build_array_type (char_type_node,
+				      build_index_type (size_int (len)));
+  TREE_READONLY (str) = 1;
+  TREE_STATIC (str) = 1;
+  CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, build_int_cst (short_unsigned_type_node,
+						       tkind));
+  CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, build_int_cst (short_unsigned_type_node,
+						       tinfo));
+  CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, str);
+
+  TREE_CONSTANT (ctor) = 1;
+  TREE_STATIC (ctor) = 1;
+  DECL_INITIAL (decl) = ctor;
+  rest_of_decl_compilation (decl, 1, 0);
+
+  /* Save the address of the VAR_DECL into the hash table.  */
+  decl = build_fold_addr_expr (decl);
+  *slot = ubsan_typedesc_new (type, decl);
+
+  return decl;
+}
+
+/* Create a structure for the ubsan library.  NAME is a name of the new
+   structure.  The arguments in ... are of __ubsan_type_descriptor type
+   and there are at most two of them.  */
+
+tree
+ubsan_create_data (const char *name, location_t loc, ...)
+{
+  va_list args;
+  tree ret, t;
+  tree fields[3];
+  vec<tree, va_gc> *saved_args = NULL;
+  size_t i = 0;
+
+  /* Firstly, create a pointer to type descriptor type.  */
+  tree td_type = ubsan_type_descriptor_type ();
+  TYPE_READONLY (td_type) = 1;
+  td_type = build_pointer_type (td_type);
+
+  /* Create the structure type.  */
+  ret = make_node (RECORD_TYPE);
+  if (loc != UNKNOWN_LOCATION)
+    {
+      fields[i] = build_decl (UNKNOWN_LOCATION, FIELD_DECL, NULL_TREE,
+			      ubsan_source_location_type ());
+      DECL_CONTEXT (fields[i]) = ret;
+      i++;
+    }
+
+  va_start (args, loc);
+  for (t = va_arg (args, tree); t != NULL_TREE;
+       i++, t = va_arg (args, tree))
+    {
+      gcc_checking_assert (i < 3);
+      /* Save the tree argument for later use.  */
+      vec_safe_push (saved_args, t);
+      fields[i] = build_decl (UNKNOWN_LOCATION, FIELD_DECL, NULL_TREE,
+			      td_type);
+      DECL_CONTEXT (fields[i]) = ret;
+      if (i)
+	DECL_CHAIN (fields[i - 1]) = fields[i];
+    }
+  TYPE_FIELDS (ret) = fields[0];
+  TYPE_NAME (ret) = get_identifier (name);
+  layout_type (ret);
+  va_end (args);
+
+  /* Now, fill in the type.  */
+  char tmp_name[32];
+  static unsigned int ubsan_var_id_num;
+  ASM_GENERATE_INTERNAL_LABEL (tmp_name, "Lubsan_data", ubsan_var_id_num++);
+  tree var = build_decl (UNKNOWN_LOCATION, VAR_DECL, get_identifier (tmp_name),
+			 ret);
+  TREE_STATIC (var) = 1;
+  TREE_PUBLIC (var) = 0;
+  DECL_ARTIFICIAL (var) = 1;
+  DECL_IGNORED_P (var) = 1;
+  DECL_EXTERNAL (var) = 0;
+
+  vec<constructor_elt, va_gc> *v;
+  vec_alloc (v, i);
+  tree ctor = build_constructor (ret, v);
+
+  /* If desirable, set the __ubsan_source_location element.  */
+  if (loc != UNKNOWN_LOCATION)
+    CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, ubsan_source_location (loc));
+
+  size_t nelts = vec_safe_length (saved_args);
+  for (i = 0; i < nelts; i++)
+    {
+      t = (*saved_args)[i];
+      CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, t);
+    }
+
+  TREE_CONSTANT (ctor) = 1;
+  TREE_STATIC (ctor) = 1;
+  DECL_INITIAL (var) = ctor;
+  rest_of_decl_compilation (var, 1, 0);
+
+  return var;
+}
+
+/* Instrument the __builtin_unreachable call.  We just call the libubsan
+   routine instead.  */
+
+tree
+ubsan_instrument_unreachable (location_t loc)
+{
+  tree data = ubsan_create_data ("__ubsan_unreachable_data", loc, NULL_TREE);
+  tree t = builtin_decl_explicit (BUILT_IN_UBSAN_HANDLE_BUILTIN_UNREACHABLE);
+  return build_call_expr_loc (loc, t, 1, build_fold_addr_expr_loc (loc, data));
+}
diff --git a/gcc/ubsan.h b/gcc/ubsan.h
new file mode 100644
index 0000000..abf4f5d
--- /dev/null
+++ b/gcc/ubsan.h
@@ -0,0 +1,30 @@
+/* UndefinedBehaviorSanitizer, undefined behavior detector.
+   Copyright (C) 2013 Free Software Foundation, Inc.
+   Contributed by Marek Polacek <polacek@redhat.com>
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#ifndef GCC_UBSAN_H
+#define GCC_UBSAN_H
+
+extern tree ubsan_instrument_unreachable (location_t);
+extern tree ubsan_create_data (const char *, location_t, ...);
+extern tree ubsan_type_descriptor (tree);
+extern tree ubsan_encode_value (tree);
+
+#endif  /* GCC_UBSAN_H  */
+
diff --git a/gcc/varasm.c b/gcc/varasm.c
index 8efd98e..7928f1a 100644
--- a/gcc/varasm.c
+++ b/gcc/varasm.c
@@ -1102,7 +1102,8 @@ get_variable_section (tree decl, bool prefer_noswitch_p)
       && bss_initializer_p (decl))
     {
       if (!TREE_PUBLIC (decl)
-	  && !(flag_asan && asan_protect_global (decl)))
+	  && !((flag_sanitize & SANITIZE_ADDRESS)
+	       && asan_protect_global (decl)))
 	return lcomm_section;
       if (bss_noswitch_section)
 	return bss_noswitch_section;
@@ -1904,7 +1905,7 @@ assemble_noswitch_variable (tree decl, const char *name, section *sect,
   size = tree_low_cst (DECL_SIZE_UNIT (decl), 1);
   rounded = size;
 
-  if (flag_asan && asan_protect_global (decl))
+  if ((flag_sanitize & SANITIZE_ADDRESS) && asan_protect_global (decl))
     size += asan_red_zone_size (size);
 
   /* Don't allocate zero bytes of common,
@@ -2063,7 +2064,7 @@ assemble_variable (tree decl, int top_level ATTRIBUTE_UNUSED,
 
   align_variable (decl, dont_output_data);
 
-  if (flag_asan
+  if ((flag_sanitize & SANITIZE_ADDRESS)
       && asan_protect_global (decl))
     {
       asan_protected = true;
@@ -3335,7 +3336,8 @@ output_constant_def_contents (rtx symbol)
   /* We are no longer deferring this constant.  */
   TREE_ASM_WRITTEN (decl) = TREE_ASM_WRITTEN (exp) = 1;
 
-  if (flag_asan && TREE_CODE (exp) == STRING_CST
+  if ((flag_sanitize & SANITIZE_ADDRESS)
+      && TREE_CODE (exp) == STRING_CST
       && asan_protect_global (exp))
     {
       asan_protected = true;
@@ -6247,7 +6249,8 @@ categorize_decl_for_section (const_tree decl, int reloc)
   else if (TREE_CODE (decl) == STRING_CST)
     {
       if (flag_mudflap
-	  || (flag_asan && asan_protect_global (CONST_CAST_TREE (decl))))
+	  || ((flag_sanitize & SANITIZE_ADDRESS)
+	      && asan_protect_global (CONST_CAST_TREE (decl))))
       /* or !flag_merge_constants */
         return SECCAT_RODATA;
       else
@@ -6273,7 +6276,8 @@ categorize_decl_for_section (const_tree decl, int reloc)
       else if (reloc & targetm.asm_out.reloc_rw_mask ())
 	ret = reloc == 1 ? SECCAT_DATA_REL_RO_LOCAL : SECCAT_DATA_REL_RO;
       else if (reloc || flag_merge_constants < 2 || flag_mudflap
-	       || (flag_asan && asan_protect_global (CONST_CAST_TREE (decl))))
+	       || ((flag_sanitize & SANITIZE_ADDRESS)
+		   && asan_protect_global (CONST_CAST_TREE (decl))))
 	/* C and C++ don't allow different variables to share the same
 	   location.  -fmerge-all-constants allows even that (at the
 	   expense of not conforming).  */
@@ -7031,7 +7035,7 @@ place_block_symbol (rtx symbol)
       decl = SYMBOL_REF_DECL (symbol);
       alignment = DECL_ALIGN (decl);
       size = get_constant_size (DECL_INITIAL (decl));
-      if (flag_asan
+      if ((flag_sanitize & SANITIZE_ADDRESS)
 	  && TREE_CODE (DECL_INITIAL (decl)) == STRING_CST
 	  && asan_protect_global (DECL_INITIAL (decl)))
 	size += asan_red_zone_size (size);
@@ -7041,7 +7045,8 @@ place_block_symbol (rtx symbol)
       decl = SYMBOL_REF_DECL (symbol);
       alignment = get_variable_align (decl);
       size = tree_low_cst (DECL_SIZE_UNIT (decl), 1);
-      if (flag_asan && asan_protect_global (decl))
+      if ((flag_sanitize & SANITIZE_ADDRESS)
+	  && asan_protect_global (decl))
 	{
 	  size += asan_red_zone_size (size);
 	  alignment = MAX (alignment,
@@ -7191,7 +7196,7 @@ output_object_block (struct object_block *block)
 				      DECL_ALIGN (decl));
 	  size = get_constant_size (DECL_INITIAL (decl));
 	  offset += size;
-	  if (flag_asan
+	  if ((flag_sanitize & SANITIZE_ADDRESS)
 	      && TREE_CODE (DECL_INITIAL (decl)) == STRING_CST
 	      && asan_protect_global (DECL_INITIAL (decl)))
 	    {
@@ -7207,7 +7212,8 @@ output_object_block (struct object_block *block)
 	  assemble_variable_contents (decl, XSTR (symbol, 0), false);
 	  size = tree_low_cst (DECL_SIZE_UNIT (decl), 1);
 	  offset += size;
-	  if (flag_asan && asan_protect_global (decl))
+	  if ((flag_sanitize & SANITIZE_ADDRESS)
+	      && asan_protect_global (decl))
 	    {
 	      size = asan_red_zone_size (size);
 	      assemble_zeros (size);

	Marek

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

* Re: Request to merge Undefined Behavior Sanitizer in
  2013-07-25 15:35 Request to merge Undefined Behavior Sanitizer in Marek Polacek
  2013-07-25 15:40 ` Marek Polacek
@ 2013-07-25 20:23 ` Jason Merrill
  2013-07-25 20:32   ` Marek Polacek
  2013-07-31 17:49   ` Request to merge Undefined Behavior Sanitizer in (take 2) Marek Polacek
  2013-07-25 22:43 ` Request to merge Undefined Behavior Sanitizer in Joseph S. Myers
  2 siblings, 2 replies; 34+ messages in thread
From: Jason Merrill @ 2013-07-25 20:23 UTC (permalink / raw)
  To: Marek Polacek, GCC Patches; +Cc: Jakub Jelinek, Jeff Law, Joseph S. Myers

On 07/25/2013 11:32 AM, Marek Polacek wrote:
> +  vec_alloc (v, 3);
> +  tree ctor = build_constructor (dtype, v);

You might use build_constructor_va instead of managing a vector directly.

Otherwise, looks fine.  If nobody else has comments, go ahead and check 
it in next week.

Jason

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

* Re: Request to merge Undefined Behavior Sanitizer in
  2013-07-25 20:23 ` Jason Merrill
@ 2013-07-25 20:32   ` Marek Polacek
  2013-07-31 17:49   ` Request to merge Undefined Behavior Sanitizer in (take 2) Marek Polacek
  1 sibling, 0 replies; 34+ messages in thread
From: Marek Polacek @ 2013-07-25 20:32 UTC (permalink / raw)
  To: Jason Merrill; +Cc: GCC Patches, Jakub Jelinek, Jeff Law, Joseph S. Myers

On Thu, Jul 25, 2013 at 04:13:29PM -0400, Jason Merrill wrote:
> On 07/25/2013 11:32 AM, Marek Polacek wrote:
> >+  vec_alloc (v, 3);
> >+  tree ctor = build_constructor (dtype, v);
> 
> You might use build_constructor_va instead of managing a vector directly.

Thanks, will give it a try.

> Otherwise, looks fine.  If nobody else has comments, go ahead and
> check it in next week.

Okay.  Thanks,

	Marek

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

* Re: Request to merge Undefined Behavior Sanitizer in
  2013-07-25 15:35 Request to merge Undefined Behavior Sanitizer in Marek Polacek
  2013-07-25 15:40 ` Marek Polacek
  2013-07-25 20:23 ` Jason Merrill
@ 2013-07-25 22:43 ` Joseph S. Myers
  2013-07-26  5:33   ` Jeff Law
                     ` (2 more replies)
  2 siblings, 3 replies; 34+ messages in thread
From: Joseph S. Myers @ 2013-07-25 22:43 UTC (permalink / raw)
  To: Marek Polacek; +Cc: GCC Patches, Jakub Jelinek, Jeff Law, Jason Merrill

On Thu, 25 Jul 2013, Marek Polacek wrote:

> So far it sanitizes division-by-zeros, shifts and
> __builtin_unreachable calls.  This is of course far from being
> complete; I intend to write more features during this 4.9 stage.

Such as everything needed for it to replace -ftrapv (for -ftrapv to become 
an alias for an appropriate subset of this option)?

What happens if you bootstrap with this enabled - do whatever failures 
appear look like genuine bugs?  Running the testsuite with a compiler 
built with this option?  Running the testsuite with this option used when 
compiling all these tests.  I guess that initially a bootstrap with this 
option may fail because of existing bugs, and so the other tests mentioned 
can't yet be run - but using this option on GCC itself, and making sure 
that as far as possible it doesn't break compiling things or change 
diagnostics generated at compile time, seem like good goals.

-- 
Joseph S. Myers
joseph@codesourcery.com

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

* Re: Request to merge Undefined Behavior Sanitizer in
  2013-07-25 15:40 ` Marek Polacek
@ 2013-07-25 22:47   ` Joseph S. Myers
  2013-07-31 12:59     ` Marek Polacek
  0 siblings, 1 reply; 34+ messages in thread
From: Joseph S. Myers @ 2013-07-25 22:47 UTC (permalink / raw)
  To: Marek Polacek; +Cc: GCC Patches, Jakub Jelinek, Jeff Law, Jason Merrill

On Thu, 25 Jul 2013, Marek Polacek wrote:

> +@item -fsanitize=undefined
> +Enable UndefinedBehaviorSanitizer, a fast undefined behavior detector
> +Various computations will be instrumented to detect
> +undefined behavior, e.g.@: division by zero or various overflows.

The same issues applies as for bounds-checking options - please give 
sufficient information in the documentation for a user to be able to judge 
the trade-offs between this and -ftrapv (for example).

It should also be clear how this interacts with -fwrapv.  I'd say that 
-fwrapv makes the semantics of overflow in signed-integer arithmetic no 
longer undefined (of course division by zero is still undefined) and so 
should mean such overflows aren't warned for.  Now, you don't currently 
have any checks this would affect (given that INT_MIN / -1 and INT_MIN % 
-1 don't currently work reliably with -fwrapv anyway), but the intention 
should be clear for when overflow checks are added.

-- 
Joseph S. Myers
joseph@codesourcery.com

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

* Re: Request to merge Undefined Behavior Sanitizer in
  2013-07-25 22:43 ` Request to merge Undefined Behavior Sanitizer in Joseph S. Myers
@ 2013-07-26  5:33   ` Jeff Law
  2013-07-26  6:06     ` Andrew Pinski
  2013-07-29 10:09     ` Marek Polacek
  2013-07-26  6:51   ` Marc Glisse
  2013-07-31 11:07   ` Marek Polacek
  2 siblings, 2 replies; 34+ messages in thread
From: Jeff Law @ 2013-07-26  5:33 UTC (permalink / raw)
  To: Joseph S. Myers; +Cc: Marek Polacek, GCC Patches, Jakub Jelinek, Jason Merrill

On 07/25/2013 04:40 PM, Joseph S. Myers wrote:
> On Thu, 25 Jul 2013, Marek Polacek wrote:
>
>> So far it sanitizes division-by-zeros, shifts and
>> __builtin_unreachable calls.  This is of course far from being
>> complete; I intend to write more features during this 4.9 stage.
>
> Such as everything needed for it to replace -ftrapv (for -ftrapv to become
> an alias for an appropriate subset of this option)?
I'm guessing Marek would probably start with looking to provide feature 
parity with LLVM's -fsanitize=undefined which is defined as:

-fsanitize=undefined: Fast and compatible undefined behavior checker. 
Enables the undefined behavior checks that have small runtime cost and 
no impact on address space layout or ABI. This includes all of the 
checks listed below other than unsigned-integer-overflow.

So I wouldn't necessarily expect ubsan, at least in the near future, to 
catch the -ftrapv stuff.  Though it's something that might be able to be 
added at some point.


> What happens if you bootstrap with this enabled - do whatever failures
> appear look like genuine bugs?  Running the testsuite with a compiler
> built with this option?  Running the testsuite with this option used when
> compiling all these tests.  I guess that initially a bootstrap with this
> option may fail because of existing bugs, and so the other tests mentioned
> can't yet be run - but using this option on GCC itself, and making sure
> that as far as possible it doesn't break compiling things or change
> diagnostics generated at compile time, seem like good goals.
Note that the instrumentation happens in c-family/ so we might not be 
fully instrumenting what comes out of the C++ front-end.  However, if 
we're getting a reasonable amount of sanitization, it'd be real 
interesting to track down any failures that trigger for bootstraps.

There are some projects out there that using ubsan (SpiderMonkey for 
example) from LLVM to root out issues.

Jeff


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

* Re: Request to merge Undefined Behavior Sanitizer in
  2013-07-26  5:33   ` Jeff Law
@ 2013-07-26  6:06     ` Andrew Pinski
  2013-07-26 12:11       ` Marek Polacek
  2013-07-26 19:25       ` Jason Merrill
  2013-07-29 10:09     ` Marek Polacek
  1 sibling, 2 replies; 34+ messages in thread
From: Andrew Pinski @ 2013-07-26  6:06 UTC (permalink / raw)
  To: Jeff Law
  Cc: Joseph S. Myers, Marek Polacek, GCC Patches, Jakub Jelinek,
	Jason Merrill

On Thu, Jul 25, 2013 at 9:50 PM, Jeff Law <law@redhat.com> wrote:
> On 07/25/2013 04:40 PM, Joseph S. Myers wrote:
>>
>> On Thu, 25 Jul 2013, Marek Polacek wrote:
>>
>>> So far it sanitizes division-by-zeros, shifts and
>>> __builtin_unreachable calls.  This is of course far from being
>>> complete; I intend to write more features during this 4.9 stage.
>>
>>
>> Such as everything needed for it to replace -ftrapv (for -ftrapv to become
>> an alias for an appropriate subset of this option)?
>
> I'm guessing Marek would probably start with looking to provide feature
> parity with LLVM's -fsanitize=undefined which is defined as:
>
> -fsanitize=undefined: Fast and compatible undefined behavior checker.
> Enables the undefined behavior checks that have small runtime cost and no
> impact on address space layout or ABI. This includes all of the checks
> listed below other than unsigned-integer-overflow.

What does it mean by "unsigned-integer-overflow"? Unsigned integers
never overflow.
Or maybe I misread the documentation here.

Thanks,
Andrew Pinski

>
> So I wouldn't necessarily expect ubsan, at least in the near future, to
> catch the -ftrapv stuff.  Though it's something that might be able to be
> added at some point.
>
>
>
>> What happens if you bootstrap with this enabled - do whatever failures
>> appear look like genuine bugs?  Running the testsuite with a compiler
>> built with this option?  Running the testsuite with this option used when
>> compiling all these tests.  I guess that initially a bootstrap with this
>> option may fail because of existing bugs, and so the other tests mentioned
>> can't yet be run - but using this option on GCC itself, and making sure
>> that as far as possible it doesn't break compiling things or change
>> diagnostics generated at compile time, seem like good goals.
>
> Note that the instrumentation happens in c-family/ so we might not be fully
> instrumenting what comes out of the C++ front-end.  However, if we're
> getting a reasonable amount of sanitization, it'd be real interesting to
> track down any failures that trigger for bootstraps.
>
> There are some projects out there that using ubsan (SpiderMonkey for
> example) from LLVM to root out issues.
>
> Jeff
>
>

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

* Re: Request to merge Undefined Behavior Sanitizer in
  2013-07-25 22:43 ` Request to merge Undefined Behavior Sanitizer in Joseph S. Myers
  2013-07-26  5:33   ` Jeff Law
@ 2013-07-26  6:51   ` Marc Glisse
  2013-08-08 15:57     ` Joseph S. Myers
  2013-07-31 11:07   ` Marek Polacek
  2 siblings, 1 reply; 34+ messages in thread
From: Marc Glisse @ 2013-07-26  6:51 UTC (permalink / raw)
  To: Joseph S. Myers
  Cc: Marek Polacek, GCC Patches, Jakub Jelinek, Jeff Law, Jason Merrill

On Thu, 25 Jul 2013, Joseph S. Myers wrote:

> On Thu, 25 Jul 2013, Marek Polacek wrote:
>
>> So far it sanitizes division-by-zeros, shifts and
>> __builtin_unreachable calls.  This is of course far from being
>> complete; I intend to write more features during this 4.9 stage.
>
> Such as everything needed for it to replace -ftrapv (for -ftrapv to become
> an alias for an appropriate subset of this option)?
>
> What happens if you bootstrap with this enabled - do whatever failures
> appear look like genuine bugs?  Running the testsuite with a compiler
> built with this option?  Running the testsuite with this option used when
> compiling all these tests.  I guess that initially a bootstrap with this
> option may fail because of existing bugs, and so the other tests mentioned
> can't yet be run - but using this option on GCC itself, and making sure
> that as far as possible it doesn't break compiling things or change
> diagnostics generated at compile time, seem like good goals.

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=57324
(that is using llvm's sanitizer)

and for a first patch (unreviewed):

http://gcc.gnu.org/ml/gcc-patches/2013-06/msg01466.html
(started at http://gcc.gnu.org/ml/gcc-patches/2013-05/msg01402.html )

-- 
Marc Glisse

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

* Re: Request to merge Undefined Behavior Sanitizer in
  2013-07-26  6:06     ` Andrew Pinski
@ 2013-07-26 12:11       ` Marek Polacek
  2013-07-26 19:25       ` Jason Merrill
  1 sibling, 0 replies; 34+ messages in thread
From: Marek Polacek @ 2013-07-26 12:11 UTC (permalink / raw)
  To: Andrew Pinski
  Cc: Jeff Law, Joseph S. Myers, GCC Patches, Jakub Jelinek, Jason Merrill

On Thu, Jul 25, 2013 at 10:33:46PM -0700, Andrew Pinski wrote:
> What does it mean by "unsigned-integer-overflow"? Unsigned integers
> never overflow.
> Or maybe I misread the documentation here.

Well, clang can sanitize even when unsigned int wraps.  But this
feature seems doubtful, I don't think I ever implement it for GCC.

	Marek

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

* Re: Request to merge Undefined Behavior Sanitizer in
  2013-07-26  6:06     ` Andrew Pinski
  2013-07-26 12:11       ` Marek Polacek
@ 2013-07-26 19:25       ` Jason Merrill
  2013-07-26 20:06         ` Marc Glisse
  1 sibling, 1 reply; 34+ messages in thread
From: Jason Merrill @ 2013-07-26 19:25 UTC (permalink / raw)
  To: Andrew Pinski, Jeff Law
  Cc: Joseph S. Myers, Marek Polacek, GCC Patches, Jakub Jelinek

On 07/26/2013 01:33 AM, Andrew Pinski wrote:
> What does it mean by "unsigned-integer-overflow"? Unsigned integers
> never overflow.

This is a common misconception.  Conversion to an unsigned integer type 
never has undefined behavior, but unsigned integer arithmetic does.  C11 
says,

If an exceptional condition occurs during the evaluation of an 
expression (that is, if the result is not mathematically defined or not 
in the range of representable values for its type), the behavior is 
undefined.

So UINT_MAX+1U has undefined behavior.

Jason

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

* Re: Request to merge Undefined Behavior Sanitizer in
  2013-07-26 19:25       ` Jason Merrill
@ 2013-07-26 20:06         ` Marc Glisse
  2013-07-26 23:07           ` Jason Merrill
  0 siblings, 1 reply; 34+ messages in thread
From: Marc Glisse @ 2013-07-26 20:06 UTC (permalink / raw)
  To: Jason Merrill
  Cc: Andrew Pinski, Jeff Law, Joseph S. Myers, Marek Polacek,
	GCC Patches, Jakub Jelinek

On Fri, 26 Jul 2013, Jason Merrill wrote:

> On 07/26/2013 01:33 AM, Andrew Pinski wrote:
>> What does it mean by "unsigned-integer-overflow"? Unsigned integers
>> never overflow.
>
> This is a common misconception.  Conversion to an unsigned integer type never 
> has undefined behavior, but unsigned integer arithmetic does.  C11 says,
>
> If an exceptional condition occurs during the evaluation of an expression 
> (that is, if the result is not mathematically defined or not in the range of 
> representable values for its type), the behavior is undefined.
>
> So UINT_MAX+1U has undefined behavior.

Uh?
C11 also says:

"A computation involving unsigned operands can never overflow, because a 
result that cannot be represented by the resulting unsigned integer type 
is reduced modulo the number that is one greater than the largest value 
that can be represented by the resulting type."

UINT_MAX+1U is mathematically well defined, it is 0U (modulo 2^N), which 
is in the range.


-- 
Marc Glisse

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

* Re: Request to merge Undefined Behavior Sanitizer in
  2013-07-26 20:06         ` Marc Glisse
@ 2013-07-26 23:07           ` Jason Merrill
  0 siblings, 0 replies; 34+ messages in thread
From: Jason Merrill @ 2013-07-26 23:07 UTC (permalink / raw)
  To: gcc-patches
  Cc: Andrew Pinski, Jeff Law, Joseph S. Myers, Marek Polacek, Jakub Jelinek

On 07/26/2013 04:00 PM, Marc Glisse wrote:
> C11 also says:
>
> "A computation involving unsigned operands can never overflow, because a
> result that cannot be represented by the resulting unsigned integer type
> is reduced modulo the number that is one greater than the largest value
> that can be represented by the resulting type."

Ah, so it does.  I agree that takes priority, though it would be nice to 
clarify the passage I quoted...

Jason

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

* Re: Request to merge Undefined Behavior Sanitizer in
  2013-07-26  5:33   ` Jeff Law
  2013-07-26  6:06     ` Andrew Pinski
@ 2013-07-29 10:09     ` Marek Polacek
  1 sibling, 0 replies; 34+ messages in thread
From: Marek Polacek @ 2013-07-29 10:09 UTC (permalink / raw)
  To: Jeff Law; +Cc: Joseph S. Myers, GCC Patches, Jakub Jelinek, Jason Merrill

On Thu, Jul 25, 2013 at 10:50:14PM -0600, Jeff Law wrote:
> On 07/25/2013 04:40 PM, Joseph S. Myers wrote:
> >On Thu, 25 Jul 2013, Marek Polacek wrote:
> >
> >>So far it sanitizes division-by-zeros, shifts and
> >>__builtin_unreachable calls.  This is of course far from being
> >>complete; I intend to write more features during this 4.9 stage.
> >
> >Such as everything needed for it to replace -ftrapv (for -ftrapv to become
> >an alias for an appropriate subset of this option)?
> I'm guessing Marek would probably start with looking to provide
> feature parity with LLVM's -fsanitize=undefined which is defined as:
> 
> -fsanitize=undefined: Fast and compatible undefined behavior
> checker. Enables the undefined behavior checks that have small
> runtime cost and no impact on address space layout or ABI. This
> includes all of the checks listed below other than
> unsigned-integer-overflow.
> 
> So I wouldn't necessarily expect ubsan, at least in the near future,
> to catch the -ftrapv stuff.  Though it's something that might be
> able to be added at some point.

Yeah, exactly.  I expect to get back to -ftrapv after providing
the most useful subset of LLVM's ubsan functionality.

	Marek

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

* Re: Request to merge Undefined Behavior Sanitizer in
  2013-07-25 22:43 ` Request to merge Undefined Behavior Sanitizer in Joseph S. Myers
  2013-07-26  5:33   ` Jeff Law
  2013-07-26  6:51   ` Marc Glisse
@ 2013-07-31 11:07   ` Marek Polacek
  2 siblings, 0 replies; 34+ messages in thread
From: Marek Polacek @ 2013-07-31 11:07 UTC (permalink / raw)
  To: Joseph S. Myers; +Cc: GCC Patches, Jakub Jelinek, Jeff Law, Jason Merrill

On Thu, Jul 25, 2013 at 10:40:22PM +0000, Joseph S. Myers wrote:
> What happens if you bootstrap with this enabled - do whatever failures 
> appear look like genuine bugs?  Running the testsuite with a compiler 
> built with this option?  Running the testsuite with this option used when 
> compiling all these tests.  I guess that initially a bootstrap with this 
> option may fail because of existing bugs, and so the other tests mentioned 
> can't yet be run - but using this option on GCC itself, and making sure 
> that as far as possible it doesn't break compiling things or change 
> diagnostics generated at compile time, seem like good goals.

The bootstrap with -fsanitize=undefined currently fails.  One issue is
http://gcc.gnu.org/ml/gcc-patches/2013-07/msg01480.html
(-Wuninitialized needs fixing I'm afraid), and another is e.g.:

  switch (i)
    {
      case 0 * (1 / 0):
        ;
    }

In the above, in C, we always fail (check_case_value issues 
"error: case label does not reduce to an integer constant").  But in C++,
with -fsanitize=undefined, we get
error: ‘__builtin___ubsan_handle_divrem_overflow((& *.Lubsan_data0), 1u, 0u)’
is not a constant expression
and without sanitizing, there's no error (of course the behavior
is undefined).  I'm not sure how to deal with this, clang in both C/C++ says
error: expression is not an integral constant expression
It seems that this should be handled in semantics.c:verify_constant,
but the function gets <integer_cst ... constant 0> as a tree parameter...

Other than that, currently no other issues leap to mind; I ran 
gcc.dg/*const-expr* tests with -fsanitize=undefined and everything's fine,
gcc.dg/overflow-warn* has some failures, all due to "case 0 * (1 / 0)" issue.

Thanks,

	Marek

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

* Re: Request to merge Undefined Behavior Sanitizer in
  2013-07-25 22:47   ` Joseph S. Myers
@ 2013-07-31 12:59     ` Marek Polacek
  0 siblings, 0 replies; 34+ messages in thread
From: Marek Polacek @ 2013-07-31 12:59 UTC (permalink / raw)
  To: Joseph S. Myers; +Cc: GCC Patches, Jakub Jelinek, Jeff Law, Jason Merrill

On Thu, Jul 25, 2013 at 10:43:30PM +0000, Joseph S. Myers wrote:
> On Thu, 25 Jul 2013, Marek Polacek wrote:
> 
> > +@item -fsanitize=undefined
> > +Enable UndefinedBehaviorSanitizer, a fast undefined behavior detector
> > +Various computations will be instrumented to detect
> > +undefined behavior, e.g.@: division by zero or various overflows.
> 
> The same issues applies as for bounds-checking options - please give 
> sufficient information in the documentation for a user to be able to judge 
> the trade-offs between this and -ftrapv (for example).

Ok, I've commited a patch which hopefully makes the documentation better:

--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -5150,8 +5150,11 @@ See @uref{http://code.google.com/p/data-race-test/wiki/ThreadSanitizer} for 
 
 @item -fsanitize=undefined
 Enable UndefinedBehaviorSanitizer, a fast undefined behavior detector
-Various computations will be instrumented to detect
-undefined behavior, e.g.@: division by zero or various overflows.
+Various computations will be instrumented to detect undefined behavior
+at runtime, e.g.@: division by zero or various overflows.
+While @option{-ftrapv} causes traps for signed overflows to be emitted,
+@option{-fsanitize=undefined} gives a diagnostic message.
+This currently works only for the C family of languages.
 
 @item -fdump-final-insns@r{[}=@var{file}@r{]}
 @opindex fdump-final-insns

> It should also be clear how this interacts with -fwrapv.  I'd say that 
> -fwrapv makes the semantics of overflow in signed-integer arithmetic no 
> longer undefined (of course division by zero is still undefined) and so 
> should mean such overflows aren't warned for.  Now, you don't currently 
> have any checks this would affect (given that INT_MIN / -1 and INT_MIN % 
> -1 don't currently work reliably with -fwrapv anyway), but the intention 
> should be clear for when overflow checks are added.

Yes, I agree.  When the signed overflows checks are in, we shouldn't sanitize
signed overflows when -fwrapv is in effect.

	Marek

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

* Re: Request to merge Undefined Behavior Sanitizer in (take 2)
  2013-07-25 20:23 ` Jason Merrill
  2013-07-25 20:32   ` Marek Polacek
@ 2013-07-31 17:49   ` Marek Polacek
  2013-07-31 19:04     ` Jason Merrill
  1 sibling, 1 reply; 34+ messages in thread
From: Marek Polacek @ 2013-07-31 17:49 UTC (permalink / raw)
  To: Jason Merrill; +Cc: GCC Patches, Jakub Jelinek, Jeff Law, Joseph S. Myers

[-- Attachment #1: Type: text/plain, Size: 1445 bytes --]

On Thu, Jul 25, 2013 at 04:13:29PM -0400, Jason Merrill wrote:
> Otherwise, looks fine.  If nobody else has comments, go ahead and
> check it in next week.

I had to make a few changes since, particularly:

 - [ubsan] Add -static-libubsan
   http://gcc.gnu.org/ml/gcc-patches/2013-07/msg01467.html
 - [ubsan] Don't try to sanitize shifts outside of functions
   http://gcc.gnu.org/ml/gcc-patches/2013-07/msg01468.html
 - [ubsan] Use build_constructor_va where possible
   http://gcc.gnu.org/ml/gcc-patches/2013-07/msg01469.html
 - [ubsan] Add bootstrap-ubsan.mk
   http://gcc.gnu.org/ml/gcc-patches/2013-07/msg01470.html
 - [ubsan] Rename obsolete variable
   http://gcc.gnu.org/ml/gcc-patches/2013-07/msg01473.html
 - [ubsan] Instrument expr only when doing shift or division
   http://gcc.gnu.org/ml/gcc-patches/2013-07/msg01529.html
 - [ubsan] Improve documentation of -fsanitize=undefined
   http://gcc.gnu.org/ml/gcc-patches/2013-07/msg01540.html
 - [ubsan] Add missing ubsan tests in g++.dg/dg.exp
   http://gcc.gnu.org/ml/gcc-patches/2013-07/msg01563.html

There are still at least two issues though, which is why
bootstrap with -fsanitize=undefined fails:

http://gcc.gnu.org/ml/gcc-patches/2013-07/msg01480.html
http://gcc.gnu.org/ml/gcc-patches/2013-07/msg01536.html

They seem to be relatively minor, but we'll have to deal
with them eventually.

Regtested/bootstrapped on both ppc64-linux and x86_64 linux,
so, ok for trunk?

	Marek

[-- Attachment #2: U.tar.bz2 --]
[-- Type: application/x-bzip2, Size: 39045 bytes --]

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

* Re: Request to merge Undefined Behavior Sanitizer in (take 2)
  2013-07-31 17:49   ` Request to merge Undefined Behavior Sanitizer in (take 2) Marek Polacek
@ 2013-07-31 19:04     ` Jason Merrill
  2013-08-01 18:06       ` Marek Polacek
  2013-08-06 14:42       ` Marek Polacek
  0 siblings, 2 replies; 34+ messages in thread
From: Jason Merrill @ 2013-07-31 19:04 UTC (permalink / raw)
  To: Marek Polacek; +Cc: GCC Patches, Jakub Jelinek, Jeff Law, Joseph S. Myers

On 07/31/2013 01:33 PM, Marek Polacek wrote:
> There are still at least two issues though, which is why
> bootstrap with -fsanitize=undefined fails:
>
> http://gcc.gnu.org/ml/gcc-patches/2013-07/msg01480.html

This looks like a serious bug, properly caught by -Wuninitialized.

> When sanitizing,
> in .uninit1 we have
>   int x.3;
>   int x.2;
>
>   <bb 2>:
>   x.3_3 = x.2_1(D) >> 1;
>   x = x.3_3;

Note that x.2 is not initialized.

> and when no sanitizing
>   int x.1;
>   int x.0;
>
>   <bb 2>:
>   x.0_2 = x;
>   x.1_3 = x.0_2 >> 1;
>   x = x.1_3;

But here x.0 is initialized.

> http://gcc.gnu.org/ml/gcc-patches/2013-07/msg01536.html

Here, the C++ compiler is wrong to fold away the division by zero, but 
given that bug the folding ought to also eliminate the call to the 
sanitize function.  Seems like you should attach the call to the 
questionable expression itself.

Jason

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

* Re: Request to merge Undefined Behavior Sanitizer in (take 2)
  2013-07-31 19:04     ` Jason Merrill
@ 2013-08-01 18:06       ` Marek Polacek
  2013-08-03 16:24         ` Jason Merrill
  2013-08-06 14:42       ` Marek Polacek
  1 sibling, 1 reply; 34+ messages in thread
From: Marek Polacek @ 2013-08-01 18:06 UTC (permalink / raw)
  To: Jason Merrill; +Cc: GCC Patches, Jakub Jelinek, Jeff Law, Joseph S. Myers

On Wed, Jul 31, 2013 at 02:52:39PM -0400, Jason Merrill wrote:
> On 07/31/2013 01:33 PM, Marek Polacek wrote:
> >There are still at least two issues though, which is why
> >bootstrap with -fsanitize=undefined fails:
> >
> >http://gcc.gnu.org/ml/gcc-patches/2013-07/msg01480.html
> 
> This looks like a serious bug, properly caught by -Wuninitialized.
> 
> >When sanitizing,
> >in .uninit1 we have
> >  int x.3;
> >  int x.2;
> >
> >  <bb 2>:
> >  x.3_3 = x.2_1(D) >> 1;
> >  x = x.3_3;
> 
> Note that x.2 is not initialized.

Uh, dunno what I was thinking.  Oh, right, the fact that x.2_1 is 
SSA_NAME_IS_DEFAULT_DEF confused me  -- I though it's actually
initialized to 0, as x is a global var...

It really is a genuine bug.  The problem can be seen when the
if-condition in the COMPOUND_EXPR doesn't contain x, e.g. in C89
mode we instrument shift with the simple check:

  int y = if ((unsigned int) SAVE_EXPR <o> > 31) 
    {   
      __builtin___ubsan_handle_shift_out_of_bounds (&*.Lubsan_data0, (unsigned long) SAVE_EXPR <x>, (unsigned long) SAVE_EXPR <o>);
    }   
  else
    {   
      0   
    }, SAVE_EXPR <x> << SAVE_EXPR <o>;;

Now, we gimplify this.  SAVE_EXPRs are evaluated only once;
in that COMPOUND_EXPR, when we first encounter SAVE_EXPR <x> and
call get_initialized_tmp_var, we get temporary value for it, x.2.
Then, in the second part of the COMPOUND_EXPR, we meet SAVE_EXPR <x>
again, but it already has been resolved, so we don't create any
initialized var for it.  But then we end up with

  if (o.1 > 31) goto <D.1462>; else goto <D.1463>;
  <D.1462>:
  D.1464 = (unsigned long) o.0;
  x.2 = x;
  D.1466 = (unsigned long) x.2;
  __builtin___ubsan_handle_shift_out_of_bounds (&*.Lubsan_data0, D.1466, D.1464);
  goto <D.1467>;
  <D.1463>:
  <D.1467>:
  y = x.2 << o.0;

which means that when o.1 > 31 is false, we jump to D.1463, but 
the x.2 is not initialized!  

What we could perhaps do is to move the x.2 = x; initialization
before the condition, so that it's always initialized.  It's not readily
obvious to me how to implement that nicely, but I could try something, if
this is the way to go.  Does anyone have a better idea?

> >and when no sanitizing
> >  int x.1;
> >  int x.0;
> >
> >  <bb 2>:
> >  x.0_2 = x;
> >  x.1_3 = x.0_2 >> 1;
> >  x = x.1_3;
> 
> But here x.0 is initialized.
> 
> >http://gcc.gnu.org/ml/gcc-patches/2013-07/msg01536.html
> 
> Here, the C++ compiler is wrong to fold away the division by zero,
> but given that bug the folding ought to also eliminate the call to
> the sanitize function.  Seems like you should attach the call to the
> questionable expression itself.

Thanks, I'll look at this later.

	Marek

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

* Re: Request to merge Undefined Behavior Sanitizer in (take 2)
  2013-08-01 18:06       ` Marek Polacek
@ 2013-08-03 16:24         ` Jason Merrill
  2013-08-05 11:25           ` Marek Polacek
  0 siblings, 1 reply; 34+ messages in thread
From: Jason Merrill @ 2013-08-03 16:24 UTC (permalink / raw)
  To: Marek Polacek; +Cc: GCC Patches, Jakub Jelinek, Jeff Law, Joseph S. Myers

On 08/01/2013 02:06 PM, Marek Polacek wrote:
> SAVE_EXPRs are evaluated only once;
> in that COMPOUND_EXPR, when we first encounter SAVE_EXPR <x> and
> call get_initialized_tmp_var, we get temporary value for it, x.2.
> Then, in the second part of the COMPOUND_EXPR, we meet SAVE_EXPR <x>
> again, but it already has been resolved, so we don't create any
> initialized var for it.

Right.  When you have a SAVE_EXPR in a conditional context, you need to 
make sure that it gets evaluated before the condition.

> What we could perhaps do is to move the x.2 = x; initialization
> before the condition, so that it's always initialized.  It's not readily
> obvious to me how to implement that nicely, but I could try something, if
> this is the way to go.  Does anyone have a better idea?

Where are the SAVE_EXPRs coming from?  It doesn't seem to me that x 
needs to be wrapped in a SAVE_EXPR at all in this case.  For cases where 
the SAVE_EXPR is needed and not used in the test, you could add the 
SAVE_EXPR before the condition with a COMPOUND_EXPR.

Jason

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

* Re: Request to merge Undefined Behavior Sanitizer in (take 2)
  2013-08-03 16:24         ` Jason Merrill
@ 2013-08-05 11:25           ` Marek Polacek
  2013-08-06 21:24             ` Jason Merrill
  0 siblings, 1 reply; 34+ messages in thread
From: Marek Polacek @ 2013-08-05 11:25 UTC (permalink / raw)
  To: Jason Merrill; +Cc: GCC Patches, Jakub Jelinek, Jeff Law, Joseph S. Myers

On Sat, Aug 03, 2013 at 12:24:32PM -0400, Jason Merrill wrote:
> Where are the SAVE_EXPRs coming from?  It doesn't seem to me that x
> needs to be wrapped in a SAVE_EXPR at all in this case.  For cases
> where the SAVE_EXPR is needed and not used in the test, you could
> add the SAVE_EXPR before the condition with a COMPOUND_EXPR.

Those SAVE_EXPRs are coming from c-typeck.c in this case:

  if (flag_sanitize & SANITIZE_UNDEFINED
      && current_function_decl != 0
      && (doing_div_or_mod || doing_shift))
    {
      /* OP0 and/or OP1 might have side-effects.  */
      op0 = c_save_expr (op0);
      op1 = c_save_expr (op1);

I've resorted to creating (SAVE_EXPR <x>, ...)  in the condition in case
we're in C89, i.e. creating COMPOUND_EXPR in the condition itself,
it seems to work pretty well.  Firstly, I added explicit (void) cast via
NOP_EXPR (as 'if ((void) x, y)' doesn't trigger -Wunused-value warning),
but that didn't seem to be necessary...

Does that look up to snuff to you?  Thanks,

2013-08-05  Marek Polacek  <polacek@redhat.com>

	* c-ubsan.c (ubsan_instrument_shift): Properly evaluate
	SAVE_EXPR even in the C89 mode.

	* gcc.dg/ubsan/save-expr-1.c: New test.

--- gcc/c-family/c-ubsan.c.mp	2013-08-05 13:13:49.245693141 +0200
+++ gcc/c-family/c-ubsan.c	2013-08-05 13:13:53.170709181 +0200
@@ -131,6 +131,12 @@ ubsan_instrument_shift (location_t loc,
 		       build_int_cst (type0, 0));
       tt = fold_build2 (TRUTH_OR_EXPR, boolean_type_node, x, tt);
     }
+
+  /* In case we have a SAVE_EXPR in a conditional context, we need to
+     make sure it gets evaluated before the condition.  */
+  if (!c_dialect_cxx () && !flag_isoc99)
+    t = fold_build2 (COMPOUND_EXPR, TREE_TYPE (t), op0, t);
+
   tree data = ubsan_create_data ("__ubsan_shift_data",
 				 loc, ubsan_type_descriptor (type0),
 				 ubsan_type_descriptor (type1), NULL_TREE);
--- gcc/testsuite/gcc.dg/ubsan/save-expr-1.c.mp	2013-08-05 13:14:51.057960067 +0200
+++ gcc/testsuite/gcc.dg/ubsan/save-expr-1.c	2013-08-05 13:17:44.582675494 +0200
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-fsanitize=shift -std=c89 -Wall -Werror -O" } */
+
+static int x;
+int
+main (void)
+{
+  int o = 1;
+  int y = x << o;
+  return y;
+}

	Marek

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

* Re: Request to merge Undefined Behavior Sanitizer in (take 2)
  2013-07-31 19:04     ` Jason Merrill
  2013-08-01 18:06       ` Marek Polacek
@ 2013-08-06 14:42       ` Marek Polacek
  2013-08-06 23:07         ` Jason Merrill
  1 sibling, 1 reply; 34+ messages in thread
From: Marek Polacek @ 2013-08-06 14:42 UTC (permalink / raw)
  To: Jason Merrill; +Cc: GCC Patches, Jakub Jelinek, Jeff Law, Joseph S. Myers

On Wed, Jul 31, 2013 at 02:52:39PM -0400, Jason Merrill wrote:
> >http://gcc.gnu.org/ml/gcc-patches/2013-07/msg01536.html
> 
> Here, the C++ compiler is wrong to fold away the division by zero,
> but given that bug the folding ought to also eliminate the call to
> the sanitize function.  Seems like you should attach the call to the
> questionable expression itself.

Hm, actually, we can't easily fold the call to the sanitize function
away, I'm afraid, if we want to do it for the 'case <something>'
case.  When we hit the DIV_EXPR in 'case 0 * (1 / 0)',
the ubsan_instrument_division gets 1 as a first argument and 0 as
a second argument, but due to fold_builds in the
ubsan_instrument_division, we replace the case value with just the call
to the __builtin___ubsan_handle_divrem_overflow.  I think, what we
could do, is to tweak verify_constant like this:

--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -6938,6 +6938,14 @@ static bool
 verify_constant (tree t, bool allow_non_constant, bool *non_constant_p,
                 bool *overflow_p)
 {
+  /* This is to handle e.g. the goofy 'case 0 * (1 / 0)' case.  */
+  if (flag_sanitize & SANITIZE_UNDEFINED
+      && TREE_CODE (t) == CALL_EXPR
+      && is_ubsan_builtin (t))
+    {
+      error ("undefined behavior occured");
+      return *non_constant_p;
+    }
   if (!*non_constant_p && !reduced_constant_expression_p (t))
     {
       if (!allow_non_constant)

The logic behind this is that when we can't easily insert the
ubsan builtin call itself (so that it would get called unconditionally
at the runtime), at least error out; at that point the behavior
is certainly undefined thus we're free to do whatever.  I'd say it's better
than to e.g. insert 0 instead of the expression and carry on.
Also, this could be useful in other situations (at places, where
we can't insert the ubsan builtin call, but we *know* that the 
behavior is undefined).  Yes, the behavior
can be undefined only at runtime, but, this would happen only when
sanitizing and in that case is desirable to report even that.
The is_ubsan_builtin fn is not yet implemented, but you get the idea.

Thoughts?  Thanks,

	Marek

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

* Re: Request to merge Undefined Behavior Sanitizer in (take 2)
  2013-08-05 11:25           ` Marek Polacek
@ 2013-08-06 21:24             ` Jason Merrill
  2013-08-07 14:58               ` Marek Polacek
  0 siblings, 1 reply; 34+ messages in thread
From: Jason Merrill @ 2013-08-06 21:24 UTC (permalink / raw)
  To: Marek Polacek; +Cc: GCC Patches, Jakub Jelinek, Jeff Law, Joseph S. Myers

On 08/05/2013 07:24 AM, Marek Polacek wrote:
> On Sat, Aug 03, 2013 at 12:24:32PM -0400, Jason Merrill wrote:
>> Where are the SAVE_EXPRs coming from?  It doesn't seem to me that x
>> needs to be wrapped in a SAVE_EXPR at all in this case.  For cases
>> where the SAVE_EXPR is needed and not used in the test, you could
>> add the SAVE_EXPR before the condition with a COMPOUND_EXPR.
>
> Those SAVE_EXPRs are coming from c-typeck.c in this case:
>
>    if (flag_sanitize & SANITIZE_UNDEFINED
>        && current_function_decl != 0
>        && (doing_div_or_mod || doing_shift))
>      {
>        /* OP0 and/or OP1 might have side-effects.  */
>        op0 = c_save_expr (op0);
>        op1 = c_save_expr (op1);

Yes, but why do we need to wrap op0 in a save_expr?  That's only 
necessary if we're going to be evaluating it twice on the same path, but 
here it's only evaluated once on each path.

Jason

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

* Re: Request to merge Undefined Behavior Sanitizer in (take 2)
  2013-08-06 14:42       ` Marek Polacek
@ 2013-08-06 23:07         ` Jason Merrill
  2013-08-07 10:07           ` Marek Polacek
  0 siblings, 1 reply; 34+ messages in thread
From: Jason Merrill @ 2013-08-06 23:07 UTC (permalink / raw)
  To: Marek Polacek; +Cc: GCC Patches, Jakub Jelinek, Jeff Law, Joseph S. Myers

On 08/06/2013 10:42 AM, Marek Polacek wrote:
> Hm, actually, we can't easily fold the call to the sanitize function
> away, I'm afraid, if we want to do it for the 'case <something>'
> case.  When we hit the DIV_EXPR in 'case 0 * (1 / 0)',
> the ubsan_instrument_division gets 1 as a first argument and 0 as
> a second argument, but due to fold_builds in the
> ubsan_instrument_division, we replace the case value with just the call
> to the __builtin___ubsan_handle_divrem_overflow.

Ah, and the call isn't folded away because it has side-effects.

> I think, what we could do, is to tweak verify_constant like this:
>
> +  /* This is to handle e.g. the goofy 'case 0 * (1 / 0)' case.  */
> +  if (flag_sanitize & SANITIZE_UNDEFINED
> +      && TREE_CODE (t) == CALL_EXPR
> +      && is_ubsan_builtin (t))
> +    {
> +      error ("undefined behavior occured");
> +      return *non_constant_p;
> +    }

I think I'd rather handle ubsan builtins specially in dump_expr.

Jason

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

* Re: Request to merge Undefined Behavior Sanitizer in (take 2)
  2013-08-06 23:07         ` Jason Merrill
@ 2013-08-07 10:07           ` Marek Polacek
  2013-08-07 14:25             ` Jason Merrill
  0 siblings, 1 reply; 34+ messages in thread
From: Marek Polacek @ 2013-08-07 10:07 UTC (permalink / raw)
  To: Jason Merrill; +Cc: GCC Patches, Jakub Jelinek, Jeff Law, Joseph S. Myers

On Tue, Aug 06, 2013 at 07:07:27PM -0400, Jason Merrill wrote:
> >I think, what we could do, is to tweak verify_constant like this:
> >
> >+  /* This is to handle e.g. the goofy 'case 0 * (1 / 0)' case.  */
> >+  if (flag_sanitize & SANITIZE_UNDEFINED
> >+      && TREE_CODE (t) == CALL_EXPR
> >+      && is_ubsan_builtin (t))
> >+    {
> >+      error ("undefined behavior occured");
> >+      return *non_constant_p;
> >+    }
> 
> I think I'd rather handle ubsan builtins specially in dump_expr.

I might've misunderstood what you mean.  If we drop the hunk above,
then we'll call 
    error ("%q+E is not a constant expression", t);
so, we'll print "is not a constant expression" no matter what, we
surely can recognize the ubsan built-ins in dump_expr, but what would
we do then?

	Marek

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

* Re: Request to merge Undefined Behavior Sanitizer in (take 2)
  2013-08-07 10:07           ` Marek Polacek
@ 2013-08-07 14:25             ` Jason Merrill
  2013-08-07 16:13               ` Marek Polacek
  0 siblings, 1 reply; 34+ messages in thread
From: Jason Merrill @ 2013-08-07 14:25 UTC (permalink / raw)
  To: Marek Polacek; +Cc: GCC Patches, Jakub Jelinek, Jeff Law, Joseph S. Myers

On 08/07/2013 06:06 AM, Marek Polacek wrote:
> I might've misunderstood what you mean.  If we drop the hunk above,
> then we'll call
>      error ("%q+E is not a constant expression", t);
> so, we'll print "is not a constant expression" no matter what

Yes, that's fine; 1/0 is not a constant expression, because it has 
undefined behavior.

> we surely can recognize the ubsan built-ins in dump_expr, but what would
> we do then?

Print something more meaningful to the user.

Jason

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

* Re: Request to merge Undefined Behavior Sanitizer in (take 2)
  2013-08-06 21:24             ` Jason Merrill
@ 2013-08-07 14:58               ` Marek Polacek
  2013-08-15 11:04                 ` Marek Polacek
  0 siblings, 1 reply; 34+ messages in thread
From: Marek Polacek @ 2013-08-07 14:58 UTC (permalink / raw)
  To: Jason Merrill; +Cc: GCC Patches, Jakub Jelinek, Jeff Law, Joseph S. Myers

On Tue, Aug 06, 2013 at 05:24:08PM -0400, Jason Merrill wrote:
> On 08/05/2013 07:24 AM, Marek Polacek wrote:
> >On Sat, Aug 03, 2013 at 12:24:32PM -0400, Jason Merrill wrote:
> >>Where are the SAVE_EXPRs coming from?  It doesn't seem to me that x
> >>needs to be wrapped in a SAVE_EXPR at all in this case.  For cases
> >>where the SAVE_EXPR is needed and not used in the test, you could
> >>add the SAVE_EXPR before the condition with a COMPOUND_EXPR.
> >
> >Those SAVE_EXPRs are coming from c-typeck.c in this case:
> >
> >   if (flag_sanitize & SANITIZE_UNDEFINED
> >       && current_function_decl != 0
> >       && (doing_div_or_mod || doing_shift))
> >     {
> >       /* OP0 and/or OP1 might have side-effects.  */
> >       op0 = c_save_expr (op0);
> >       op1 = c_save_expr (op1);
> 
> Yes, but why do we need to wrap op0 in a save_expr?  That's only
> necessary if we're going to be evaluating it twice on the same path,
> but here it's only evaluated once on each path.

True, in this particular case wrapping x in the SAVE_EXPR isn't
needed, thus the following should work equally:

--- a/gcc/c/c-typeck.c
+++ b/gcc/c/c-typeck.c
@@ -10493,9 +10493,12 @@ build_binary_op (location_t location, enum tree_code code,
       && (doing_div_or_mod || doing_shift))
     {
       /* OP0 and/or OP1 might have side-effects.  */
-      op0 = c_save_expr (op0);
+      if (!doing_shift || flag_isoc99)
+        {
+          op0 = c_save_expr (op0);
+          op0 = c_fully_fold (op0, false, NULL);
+       }
       op1 = c_save_expr (op1);
-      op0 = c_fully_fold (op0, false, NULL);
       op1 = c_fully_fold (op1, false, NULL);
       if (doing_div_or_mod)
        instrument_expr = ubsan_instrument_division (location, op0, op1);

(It would merit a comment, for sure.) 
I actually don't know what I prefer more, but if you like this version
more, I'll go with it.  Maybe this is better because we don't have to
create SAVE_EXPR and also we avoid one fold_build call.  Thanks,

	Marek

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

* Re: Request to merge Undefined Behavior Sanitizer in (take 2)
  2013-08-07 14:25             ` Jason Merrill
@ 2013-08-07 16:13               ` Marek Polacek
  2013-08-15  8:00                 ` Marek Polacek
  0 siblings, 1 reply; 34+ messages in thread
From: Marek Polacek @ 2013-08-07 16:13 UTC (permalink / raw)
  To: Jason Merrill; +Cc: GCC Patches, Jakub Jelinek, Jeff Law, Joseph S. Myers

On Wed, Aug 07, 2013 at 10:24:59AM -0400, Jason Merrill wrote:
> On 08/07/2013 06:06 AM, Marek Polacek wrote:
> >I might've misunderstood what you mean.  If we drop the hunk above,
> >then we'll call
> >     error ("%q+E is not a constant expression", t);
> >so, we'll print "is not a constant expression" no matter what
> 
> Yes, that's fine; 1/0 is not a constant expression, because it has
> undefined behavior.

Indeed.

> Print something more meaningful to the user.

Something along these lines?  (Not including CL/testcase yet on purpose.)
In beforementioned situation it'd print:

w.C:7:22: error: ‘<ubsan routine call>’ is not a constant expression
       case 0 * (1 / 0):
                      ^
I'm not entirely happy about it, on the other hand, this situation
should be very rare...

diff --git a/gcc/cp/error.c b/gcc/cp/error.c
index 440169a..db50b5f 100644
--- a/gcc/cp/error.c
+++ b/gcc/cp/error.c
@@ -32,6 +32,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-pretty-print.h"
 #include "pointer-set.h"
 #include "c-family/c-objc.h"
+#include "ubsan.h"
 
 #define pp_separate_with_comma(PP) pp_cxx_separate_with (PP, ',')
 #define pp_separate_with_semicolon(PP) pp_cxx_separate_with (PP, ';')
@@ -1972,6 +1973,12 @@ dump_expr (tree t, int flags)
 	      }
 	    skipfirst = true;
 	  }
+	if (flag_sanitize & SANITIZE_UNDEFINED
+	    && is_ubsan_builtin_p (fn))
+	  {
+	    pp_string (cxx_pp, M_("<ubsan routine call>"));
+	    break;
+	  }
 	dump_expr (fn, flags | TFF_EXPR_IN_PARENS);
 	dump_call_expr_args (t, flags, skipfirst);
       }
diff --git a/gcc/ubsan.c b/gcc/ubsan.c
index 8135cc9..565758d 100644
--- a/gcc/ubsan.c
+++ b/gcc/ubsan.c
@@ -456,3 +456,13 @@ ubsan_instrument_unreachable (location_t loc)
   tree t = builtin_decl_explicit (BUILT_IN_UBSAN_HANDLE_BUILTIN_UNREACHABLE);
   return build_call_expr_loc (loc, t, 1, build_fold_addr_expr_loc (loc, data));
 }
+
+/* Return true if T is a call to a libubsan routine.  */
+
+bool
+is_ubsan_builtin_p (tree t)
+{
+  gcc_checking_assert (TREE_CODE (t) == FUNCTION_DECL);
+  return strncmp (IDENTIFIER_POINTER (DECL_NAME (t)),
+		  "__builtin___ubsan_", 18) == 0;
+}
diff --git a/gcc/ubsan.h b/gcc/ubsan.h
index abf4f5d..3553a6c 100644
--- a/gcc/ubsan.h
+++ b/gcc/ubsan.h
@@ -25,6 +25,7 @@ extern tree ubsan_instrument_unreachable (location_t);
 extern tree ubsan_create_data (const char *, location_t, ...);
 extern tree ubsan_type_descriptor (tree);
 extern tree ubsan_encode_value (tree);
+extern bool is_ubsan_builtin_p (tree);
 
 #endif  /* GCC_UBSAN_H  */
 
	Marek

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

* Re: Request to merge Undefined Behavior Sanitizer in
  2013-07-26  6:51   ` Marc Glisse
@ 2013-08-08 15:57     ` Joseph S. Myers
  2013-08-23 23:23       ` Marc Glisse
  0 siblings, 1 reply; 34+ messages in thread
From: Joseph S. Myers @ 2013-08-08 15:57 UTC (permalink / raw)
  To: Marc Glisse
  Cc: Marek Polacek, GCC Patches, Jakub Jelinek, Jeff Law, Jason Merrill

On Fri, 26 Jul 2013, Marc Glisse wrote:

> http://gcc.gnu.org/bugzilla/show_bug.cgi?id=57324
> (that is using llvm's sanitizer)
> 
> and for a first patch (unreviewed):
> 
> http://gcc.gnu.org/ml/gcc-patches/2013-06/msg01466.html
> (started at http://gcc.gnu.org/ml/gcc-patches/2013-05/msg01402.html )

That patch is OK.  Of course we'll want problems that show up when the 
testsuite is run with a compiler built with sanitization enabled to be 
fixed, as well as those that show up in a simple build of the compiler and 
its libraries, but it makes sense to fix the latter first.  (And as the 
relevant functionality gets added to GCC's sanitizer, issues that show up 
in bootstrap with it enabled will need fixing as well.)

-- 
Joseph S. Myers
joseph@codesourcery.com

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

* Re: Request to merge Undefined Behavior Sanitizer in (take 2)
  2013-08-07 16:13               ` Marek Polacek
@ 2013-08-15  8:00                 ` Marek Polacek
  2013-08-15 15:29                   ` Jason Merrill
  0 siblings, 1 reply; 34+ messages in thread
From: Marek Polacek @ 2013-08-15  8:00 UTC (permalink / raw)
  To: Jason Merrill; +Cc: GCC Patches, Jakub Jelinek, Jeff Law, Joseph S. Myers

Ping.

On Wed, Aug 07, 2013 at 06:12:58PM +0200, Marek Polacek wrote:
> On Wed, Aug 07, 2013 at 10:24:59AM -0400, Jason Merrill wrote:
> > On 08/07/2013 06:06 AM, Marek Polacek wrote:
> > >I might've misunderstood what you mean.  If we drop the hunk above,
> > >then we'll call
> > >     error ("%q+E is not a constant expression", t);
> > >so, we'll print "is not a constant expression" no matter what
> > 
> > Yes, that's fine; 1/0 is not a constant expression, because it has
> > undefined behavior.
> 
> Indeed.
> 
> > Print something more meaningful to the user.
> 
> Something along these lines?  (Not including CL/testcase yet on purpose.)
> In beforementioned situation it'd print:
> 
> w.C:7:22: error: ‘<ubsan routine call>’ is not a constant expression
>        case 0 * (1 / 0):
>                       ^
> I'm not entirely happy about it, on the other hand, this situation
> should be very rare...
> 
> diff --git a/gcc/cp/error.c b/gcc/cp/error.c
> index 440169a..db50b5f 100644
> --- a/gcc/cp/error.c
> +++ b/gcc/cp/error.c
> @@ -32,6 +32,7 @@ along with GCC; see the file COPYING3.  If not see
>  #include "tree-pretty-print.h"
>  #include "pointer-set.h"
>  #include "c-family/c-objc.h"
> +#include "ubsan.h"
>  
>  #define pp_separate_with_comma(PP) pp_cxx_separate_with (PP, ',')
>  #define pp_separate_with_semicolon(PP) pp_cxx_separate_with (PP, ';')
> @@ -1972,6 +1973,12 @@ dump_expr (tree t, int flags)
>  	      }
>  	    skipfirst = true;
>  	  }
> +	if (flag_sanitize & SANITIZE_UNDEFINED
> +	    && is_ubsan_builtin_p (fn))
> +	  {
> +	    pp_string (cxx_pp, M_("<ubsan routine call>"));
> +	    break;
> +	  }
>  	dump_expr (fn, flags | TFF_EXPR_IN_PARENS);
>  	dump_call_expr_args (t, flags, skipfirst);
>        }
> diff --git a/gcc/ubsan.c b/gcc/ubsan.c
> index 8135cc9..565758d 100644
> --- a/gcc/ubsan.c
> +++ b/gcc/ubsan.c
> @@ -456,3 +456,13 @@ ubsan_instrument_unreachable (location_t loc)
>    tree t = builtin_decl_explicit (BUILT_IN_UBSAN_HANDLE_BUILTIN_UNREACHABLE);
>    return build_call_expr_loc (loc, t, 1, build_fold_addr_expr_loc (loc, data));
>  }
> +
> +/* Return true if T is a call to a libubsan routine.  */
> +
> +bool
> +is_ubsan_builtin_p (tree t)
> +{
> +  gcc_checking_assert (TREE_CODE (t) == FUNCTION_DECL);
> +  return strncmp (IDENTIFIER_POINTER (DECL_NAME (t)),
> +		  "__builtin___ubsan_", 18) == 0;
> +}
> diff --git a/gcc/ubsan.h b/gcc/ubsan.h
> index abf4f5d..3553a6c 100644
> --- a/gcc/ubsan.h
> +++ b/gcc/ubsan.h
> @@ -25,6 +25,7 @@ extern tree ubsan_instrument_unreachable (location_t);
>  extern tree ubsan_create_data (const char *, location_t, ...);
>  extern tree ubsan_type_descriptor (tree);
>  extern tree ubsan_encode_value (tree);
> +extern bool is_ubsan_builtin_p (tree);
>  
>  #endif  /* GCC_UBSAN_H  */

	Marek

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

* Re: Request to merge Undefined Behavior Sanitizer in (take 2)
  2013-08-07 14:58               ` Marek Polacek
@ 2013-08-15 11:04                 ` Marek Polacek
  2013-08-15 15:45                   ` Jason Merrill
  0 siblings, 1 reply; 34+ messages in thread
From: Marek Polacek @ 2013-08-15 11:04 UTC (permalink / raw)
  To: Jason Merrill; +Cc: GCC Patches, Jakub Jelinek, Jeff Law, Joseph S. Myers

On Wed, Aug 07, 2013 at 04:58:03PM +0200, Marek Polacek wrote:
> I actually don't know what I prefer more, but if you like this version
> more, I'll go with it.  Maybe this is better because we don't have to
> create SAVE_EXPR and also we avoid one fold_build call.  Thanks,

Not creating the SAVE_EXPRs turned to be a no-go: firstly, the logic
when to create the SAVE_EXPRs and when not is hard-to-follow (depends
on C/C++, depends on various standards and it also depends on whether
the types are signed or not) - both for shift and division.  Moreover,
when we have nested expressions like e.g.

  (i << u) << x

if any of the operands is wrapped in SAVE_EXPR, we get an
-Wuninitialized warning.  So, what I did is to evaluate
the op0 always in the condition, like "if (op0, <cond>)",
which is safe and all the uninitialized warnings are gone,
now the bootstrap with -fsanitize=undefined finally finishes.
(albeit with 
Comparing stages 2 and 3 
warning: gcc/cc1plus-checksum.o differs
warning: gcc/cc1-checksum.o differs
Bootstrap comparison failure!
gcc/combine.o differs
gcc/tree-ssa-loop-ivopts.o differs
gcc/rtlanal.o differs
gcc/calls.o differs
gcc/emit-rtl.o differs
gcc/dbxout.o differs
gcc/function.o differs
gcc/cfgexpand.o differs
gcc/stor-layout.o differs
gcc/tree.o differs
gcc/tree-vect-generic.o differs
gcc/expr.o differs
gcc/fixed-value.o differs
gcc/fold-const.o differs
gcc/i386.o differs
libdecnumber/decimal64.o differs
libdecnumber/decNumber.o differs
make[2]: *** [compare] Error 1
).

Tested x86_64-pc-linux-gnu, applying to the ubsan branch.

2013-08-15  Marek Polacek  <polacek@redhat.com>

	* c-ubsan.c (ubsan_instrument_division): Evaluate SAVE_EXPRs
	before the condition.
	(ubsan_instrument_shift): Likewise.

	* c-c++-common/ubsan/save-expr-1.c: New test.
	* c-c++-common/ubsan/save-expr-2.c: New test.
	* c-c++-common/ubsan/save-expr-3.c: New test.
	* c-c++-common/ubsan/save-expr-4.c: New test.

--- gcc/c-family/c-ubsan.c.mp	2013-08-15 10:44:51.189966522 +0200
+++ gcc/c-family/c-ubsan.c	2013-08-15 12:43:30.454523049 +0200
@@ -73,6 +73,10 @@ ubsan_instrument_division (location_t lo
       x = fold_build2 (TRUTH_AND_EXPR, boolean_type_node, x, tt);
       t = fold_build2 (TRUTH_OR_EXPR, boolean_type_node, t, x);
     }
+
+  /* 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, ubsan_type_descriptor (type),
 				 NULL_TREE);
@@ -133,6 +137,10 @@ ubsan_instrument_shift (location_t loc,
 		       build_int_cst (type0, 0));
       tt = fold_build2 (TRUTH_OR_EXPR, boolean_type_node, x, tt);
     }
+
+  /* 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, ubsan_type_descriptor (type0),
 				 ubsan_type_descriptor (type1), NULL_TREE);
--- gcc/testsuite/c-c++-common/ubsan/save-expr-1.c.mp	2013-08-15 10:45:37.377057713 +0200
+++ gcc/testsuite/c-c++-common/ubsan/save-expr-1.c	2013-08-15 10:53:01.601695980 +0200
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-fsanitize=shift -Wall -Werror -O" } */
+
+static int x;
+int
+main (void)
+{
+  int o = 1;
+  int y = x << o;
+  return y;
+}
--- gcc/testsuite/c-c++-common/ubsan/save-expr-2.c.mp	2013-08-15 10:58:37.505938910 +0200
+++ gcc/testsuite/c-c++-common/ubsan/save-expr-2.c	2013-08-15 10:58:30.258913139 +0200
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-fsanitize=shift -Wall -Werror -O" } */
+
+int
+foo (int i, unsigned int u)
+{
+  return u / i;
+}
+
+int
+bar (int i, unsigned int u)
+{
+  return u % i;
+}
--- gcc/testsuite/c-c++-common/ubsan/save-expr-3.c.mp	2013-08-15 11:02:39.111142875 +0200
+++ gcc/testsuite/c-c++-common/ubsan/save-expr-3.c	2013-08-15 11:02:34.874127652 +0200
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+/* { dg-options "-fsanitize=shift -Wall -Werror -O" } */
+
+int x;
+
+int
+foo (int i, int u)
+{
+  return (i << u) << x;
+}
+
+int
+bar (int i, int u)
+{
+  return (i >> u) >> x;
+}
--- gcc/testsuite/c-c++-common/ubsan/save-expr-4.c.mp	2013-08-15 11:09:53.453746629 +0200
+++ gcc/testsuite/c-c++-common/ubsan/save-expr-4.c	2013-08-15 11:09:45.238716728 +0200
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+/* { dg-options "-fsanitize=shift -Wall -Werror -O" } */
+
+int x;
+
+int
+foo (int i, unsigned int u)
+{
+  return (i % u) << (x / u);
+}
+
+int
+bar (int i, unsigned int u)
+{
+  return (((x % u) << (u / i)) >> x);
+}

	Marek

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

* Re: Request to merge Undefined Behavior Sanitizer in (take 2)
  2013-08-15  8:00                 ` Marek Polacek
@ 2013-08-15 15:29                   ` Jason Merrill
  0 siblings, 0 replies; 34+ messages in thread
From: Jason Merrill @ 2013-08-15 15:29 UTC (permalink / raw)
  To: Marek Polacek; +Cc: GCC Patches, Jakub Jelinek, Jeff Law, Joseph S. Myers

OK.

Jason

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

* Re: Request to merge Undefined Behavior Sanitizer in (take 2)
  2013-08-15 11:04                 ` Marek Polacek
@ 2013-08-15 15:45                   ` Jason Merrill
  0 siblings, 0 replies; 34+ messages in thread
From: Jason Merrill @ 2013-08-15 15:45 UTC (permalink / raw)
  To: Marek Polacek; +Cc: GCC Patches, Jakub Jelinek, Jeff Law, Joseph S. Myers

On 08/15/2013 07:04 AM, Marek Polacek wrote:
> if any of the operands is wrapped in SAVE_EXPR, we get an
> -Wuninitialized warning.  So, what I did is to evaluate
> the op0 always in the condition, like "if (op0, <cond>)",
> which is safe and all the uninitialized warnings are gone,

That sounds fine.

> now the bootstrap with -fsanitize=undefined finally finishes.
> (albeit with
> Bootstrap comparison failure!

That's not so fine.  :)

Jason

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

* Re: Request to merge Undefined Behavior Sanitizer in
  2013-08-08 15:57     ` Joseph S. Myers
@ 2013-08-23 23:23       ` Marc Glisse
  0 siblings, 0 replies; 34+ messages in thread
From: Marc Glisse @ 2013-08-23 23:23 UTC (permalink / raw)
  To: Joseph S. Myers; +Cc: GCC Patches

On Thu, 8 Aug 2013, Joseph S. Myers wrote:

> On Fri, 26 Jul 2013, Marc Glisse wrote:
>
>> http://gcc.gnu.org/bugzilla/show_bug.cgi?id=57324
>> (that is using llvm's sanitizer)
>>
>> and for a first patch (unreviewed):
>>
>> http://gcc.gnu.org/ml/gcc-patches/2013-06/msg01466.html
>> (started at http://gcc.gnu.org/ml/gcc-patches/2013-05/msg01402.html )
>
> That patch is OK.

Applied at r201953 after retesting, thanks.

-- 
Marc Glisse

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

end of thread, other threads:[~2013-08-23 22:19 UTC | newest]

Thread overview: 34+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-07-25 15:35 Request to merge Undefined Behavior Sanitizer in Marek Polacek
2013-07-25 15:40 ` Marek Polacek
2013-07-25 22:47   ` Joseph S. Myers
2013-07-31 12:59     ` Marek Polacek
2013-07-25 20:23 ` Jason Merrill
2013-07-25 20:32   ` Marek Polacek
2013-07-31 17:49   ` Request to merge Undefined Behavior Sanitizer in (take 2) Marek Polacek
2013-07-31 19:04     ` Jason Merrill
2013-08-01 18:06       ` Marek Polacek
2013-08-03 16:24         ` Jason Merrill
2013-08-05 11:25           ` Marek Polacek
2013-08-06 21:24             ` Jason Merrill
2013-08-07 14:58               ` Marek Polacek
2013-08-15 11:04                 ` Marek Polacek
2013-08-15 15:45                   ` Jason Merrill
2013-08-06 14:42       ` Marek Polacek
2013-08-06 23:07         ` Jason Merrill
2013-08-07 10:07           ` Marek Polacek
2013-08-07 14:25             ` Jason Merrill
2013-08-07 16:13               ` Marek Polacek
2013-08-15  8:00                 ` Marek Polacek
2013-08-15 15:29                   ` Jason Merrill
2013-07-25 22:43 ` Request to merge Undefined Behavior Sanitizer in Joseph S. Myers
2013-07-26  5:33   ` Jeff Law
2013-07-26  6:06     ` Andrew Pinski
2013-07-26 12:11       ` Marek Polacek
2013-07-26 19:25       ` Jason Merrill
2013-07-26 20:06         ` Marc Glisse
2013-07-26 23:07           ` Jason Merrill
2013-07-29 10:09     ` Marek Polacek
2013-07-26  6:51   ` Marc Glisse
2013-08-08 15:57     ` Joseph S. Myers
2013-08-23 23:23       ` Marc Glisse
2013-07-31 11:07   ` 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).