Patchwork Request to merge Undefined Behavior Sanitizer in (take 3)

login
register
mail settings
Submitter Marek Polacek
Date Aug. 30, 2013, 8:38 a.m.
Message ID <20130830083850.GE23899@redhat.com>
Download mbox | patch
Permalink /patch/271174/
State New
Headers show

Comments

Marek Polacek - Aug. 30, 2013, 8:38 a.m.
On Fri, Aug 30, 2013 at 10:15:44AM +0200, Jakub Jelinek wrote:
> So, can you please post a new final patch for the merge (with the new directories
> or files in libsanitizer/ just listed in the ChangeLog entries, but not
> actually included in the patch, that would make it too large and anyone can
> look at libsanitizer/ubsan/ on the branch)?

Yep.  This is diff between trunk and the ubsan branch without new
files.

BTW, when merging the ChangeLog.ubsan into normal ChangeLog, should I
change the CL entry dates to the day of the merge into the trunk, or 
can I keep them as they are?

	Marek
Jakub Jelinek - Aug. 30, 2013, 8:42 a.m.
On Fri, Aug 30, 2013 at 10:38:51AM +0200, Marek Polacek wrote:
> On Fri, Aug 30, 2013 at 10:15:44AM +0200, Jakub Jelinek wrote:
> > So, can you please post a new final patch for the merge (with the new directories
> > or files in libsanitizer/ just listed in the ChangeLog entries, but not
> > actually included in the patch, that would make it too large and anyone can
> > look at libsanitizer/ubsan/ on the branch)?
> 
> Yep.  This is diff between trunk and the ubsan branch without new
> files.
> 
> BTW, when merging the ChangeLog.ubsan into normal ChangeLog, should I
> change the CL entry dates to the day of the merge into the trunk, or 
> can I keep them as they are?

Usually you write a new ChangeLog entry (per changed directory) that
summarizes all the changes, using the current date.  So, e.g. for the new
files you just mention * ubsan.c: New file. etc. and don't list all the
follow-up changes.

	Jakub
Marek Polacek - Aug. 30, 2013, 12:23 p.m.
On Fri, Aug 30, 2013 at 10:42:57AM +0200, Jakub Jelinek wrote:
> On Fri, Aug 30, 2013 at 10:38:51AM +0200, Marek Polacek wrote:
> > On Fri, Aug 30, 2013 at 10:15:44AM +0200, Jakub Jelinek wrote:
> > > So, can you please post a new final patch for the merge (with the new directories
> > > or files in libsanitizer/ just listed in the ChangeLog entries, but not
> > > actually included in the patch, that would make it too large and anyone can
> > > look at libsanitizer/ubsan/ on the branch)?
> > 
> > Yep.  This is diff between trunk and the ubsan branch without new
> > files.
> > 
> > BTW, when merging the ChangeLog.ubsan into normal ChangeLog, should I
> > change the CL entry dates to the day of the merge into the trunk, or 
> > can I keep them as they are?
> 
> Usually you write a new ChangeLog entry (per changed directory) that
> summarizes all the changes, using the current date.  So, e.g. for the new
> files you just mention * ubsan.c: New file. etc. and don't list all the
> follow-up changes.

I see.  For the record, here are the new ChangeLog entries I'm going
to use when doing the merge.

config/ChangeLog
2013-08-30  Marek Polacek  <polacek@redhat.com>

	* bootstrap-ubsan.mk: New.

gcc/c-family/ChangeLog
2013-08-30  Marek Polacek  <polacek@redhat.com>

	* c-ubsan.c: New file.
	* c-ubsan.h: New file.

gcc/ChangeLog
2013-08-30  Marek Polacek  <polacek@redhat.com>

	* Makefile.in (ubsan.o): Add.
	(c-family/c-ubsan.o): Add.
	(builtins.o): Add ubsan.h dependency.
	* ubsan.h: New file.
	* ubsan.c: New file.
	* common.opt: Add -fsanitize=undefined option.
	(flag_sanitize): Add variable.
	(fsanitize=): Add option.  Add Driver.
	(fsanitize=thread): Remove option.
	(fsanitize=address): Likewise.
	(static-libubsan): New option.
	* doc/invoke.texi: Document the new flag and -static-libubsan.
	* sanitizer.def (DEF_SANITIZER_BUILTIN): Define.
	(BUILT_IN_UBSAN_HANDLE_BUILTIN_UNREACHABLE): Define.
	* builtin-attrs.def (ATTR_COLD): Define.
	(ATTR_COLD_NOTHROW_LEAF_LIST): Define.
	* builtins.def (BUILT_IN_UBSAN_HANDLE_DIVREM_OVERFLOW,
	BUILT_IN_UBSAN_HANDLE_SHIFT_OUT_OF_BOUNDS): Define.
	* flag-types.h (sanitize_code): New enum.
	* opts.c (common_handle_option): Parse command line arguments
	of -fsanitize=.  Add -fsanitize=unreachable option.
	* 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.
	(initialize_sanitizer_builtins): Build BT_FN_VOID_PTR_PTR_PTR.
	(ATTR_COLD_NOTHROW_LEAF_LIST): Define.
	(asan_global_struct): Use pointer_sized_int_node instead
	calling build_nonstandard_integer_type.
	(initialize_sanitizer_builtins): Likewise.
	(asan_finish_file): Likewise.
	* gcc.c: Document %{%:function(args):X}.
	(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.
	(ADD_STATIC_LIBUBSAN_LIBS): Define.
	(LIBUBSAN_SPEC): Likewise.
	(LIBUBSAN_EARLY_SPEC): Likewise.
	(SANITIZER_SPEC): Handle libubsan.
	(SANITIZER_EARLY_SPEC): Likewise.
	* 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*.
	* builtins.c: Include ubsan.h.
	(fold_builtin_0): Instrument __builtin_unreachable.
	* config/rs6000/rs6000.h (FRAME_GROWS_DOWNWARD): Use flag_sanitize
	instead of flag_asan.
	* tree.h (enum tree_index): Add TI_POINTER_SIZED_TYPE.
	(pointer_sized_int_node): Define.
	* tree.c (build_common_tree_nodes): Initialize
	pointer_sized_int_node.

gcc/cp/ChangeLog
2013-08-30  Marek Polacek  <polacek@redhat.com>

	* typeck.c (cp_build_binary_op): Add division by zero and shift
	instrumentation.
	* error.c (dump_expr): Special-case ubsan builtins.

gcc/c/ChangeLog
2013-08-30  Marek Polacek  <polacek@redhat.com>

	* c-typeck.c (build_binary_op): Add division by zero and shift
	instrumentation.

gcc/testsuite/ChangeLog
2013-08-30  Marek Polacek  <polacek@redhat.com>

	* g++.dg/ubsan/div-by-zero-1.C: New test.
	* 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.
	* c-c++-common/ubsan/typedef-1.c: New test.
	* c-c++-common/ubsan/const-char-1.c: New test.
	* c-c++-common/ubsan/const-expr.c: New test.
	* 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.
	* lib/ubsan-dg.exp: New file.
	* g++.dg/dg.exp: Add ubsan tests.
	* 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.

	Marek
Jakub Jelinek - Aug. 30, 2013, 12:29 p.m.
On Fri, Aug 30, 2013 at 02:23:44PM +0200, Marek Polacek wrote:
> I see.  For the record, here are the new ChangeLog entries I'm going
> to use when doing the merge.

Ok for trunk, thanks.

> config/ChangeLog
> 2013-08-30  Marek Polacek  <polacek@redhat.com>
> 
> 	* bootstrap-ubsan.mk: New.
> 
> gcc/c-family/ChangeLog
> 2013-08-30  Marek Polacek  <polacek@redhat.com>
> 
> 	* c-ubsan.c: New file.
> 	* c-ubsan.h: New file.
> 
> gcc/ChangeLog
> 2013-08-30  Marek Polacek  <polacek@redhat.com>
> 
> 	* Makefile.in (ubsan.o): Add.
> 	(c-family/c-ubsan.o): Add.
> 	(builtins.o): Add ubsan.h dependency.
> 	* ubsan.h: New file.
> 	* ubsan.c: New file.
> 	* common.opt: Add -fsanitize=undefined option.
> 	(flag_sanitize): Add variable.
> 	(fsanitize=): Add option.  Add Driver.
> 	(fsanitize=thread): Remove option.
> 	(fsanitize=address): Likewise.
> 	(static-libubsan): New option.
> 	* doc/invoke.texi: Document the new flag and -static-libubsan.
> 	* sanitizer.def (DEF_SANITIZER_BUILTIN): Define.
> 	(BUILT_IN_UBSAN_HANDLE_BUILTIN_UNREACHABLE): Define.
> 	* builtin-attrs.def (ATTR_COLD): Define.
> 	(ATTR_COLD_NOTHROW_LEAF_LIST): Define.
> 	* builtins.def (BUILT_IN_UBSAN_HANDLE_DIVREM_OVERFLOW,
> 	BUILT_IN_UBSAN_HANDLE_SHIFT_OUT_OF_BOUNDS): Define.
> 	* flag-types.h (sanitize_code): New enum.
> 	* opts.c (common_handle_option): Parse command line arguments
> 	of -fsanitize=.  Add -fsanitize=unreachable option.
> 	* 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.
> 	(initialize_sanitizer_builtins): Build BT_FN_VOID_PTR_PTR_PTR.
> 	(ATTR_COLD_NOTHROW_LEAF_LIST): Define.
> 	(asan_global_struct): Use pointer_sized_int_node instead
> 	calling build_nonstandard_integer_type.
> 	(initialize_sanitizer_builtins): Likewise.
> 	(asan_finish_file): Likewise.
> 	* gcc.c: Document %{%:function(args):X}.
> 	(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.
> 	(ADD_STATIC_LIBUBSAN_LIBS): Define.
> 	(LIBUBSAN_SPEC): Likewise.
> 	(LIBUBSAN_EARLY_SPEC): Likewise.
> 	(SANITIZER_SPEC): Handle libubsan.
> 	(SANITIZER_EARLY_SPEC): Likewise.
> 	* 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*.
> 	* builtins.c: Include ubsan.h.
> 	(fold_builtin_0): Instrument __builtin_unreachable.
> 	* config/rs6000/rs6000.h (FRAME_GROWS_DOWNWARD): Use flag_sanitize
> 	instead of flag_asan.
> 	* tree.h (enum tree_index): Add TI_POINTER_SIZED_TYPE.
> 	(pointer_sized_int_node): Define.
> 	* tree.c (build_common_tree_nodes): Initialize
> 	pointer_sized_int_node.
> 
> gcc/cp/ChangeLog
> 2013-08-30  Marek Polacek  <polacek@redhat.com>
> 
> 	* typeck.c (cp_build_binary_op): Add division by zero and shift
> 	instrumentation.
> 	* error.c (dump_expr): Special-case ubsan builtins.
> 
> gcc/c/ChangeLog
> 2013-08-30  Marek Polacek  <polacek@redhat.com>
> 
> 	* c-typeck.c (build_binary_op): Add division by zero and shift
> 	instrumentation.
> 
> gcc/testsuite/ChangeLog
> 2013-08-30  Marek Polacek  <polacek@redhat.com>
> 
> 	* g++.dg/ubsan/div-by-zero-1.C: New test.
> 	* 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.
> 	* c-c++-common/ubsan/typedef-1.c: New test.
> 	* c-c++-common/ubsan/const-char-1.c: New test.
> 	* c-c++-common/ubsan/const-expr.c: New test.
> 	* 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.
> 	* lib/ubsan-dg.exp: New file.
> 	* g++.dg/dg.exp: Add ubsan tests.
> 	* 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.

	Jakub

Patch

diff --git a/config/ChangeLog.ubsan b/config/ChangeLog.ubsan
new file mode 100644
index 0000000..2286374
--- /dev/null
+++ b/config/ChangeLog.ubsan
@@ -0,0 +1,7 @@ 
+2013-08-14  Marek Polacek  <polacek@redhat.com>
+
+	* bootstrap-ubsan.mk (POSTSTAGE1_LDFLAGS): Add -lpthread.
+
+2013-07-30  Marek Polacek  <polacek@redhat.com>
+
+	* bootstrap-ubsan.mk: New.
diff --git a/config/bootstrap-ubsan.mk b/config/bootstrap-ubsan.mk
new file mode 100644
index 0000000..2d21e83
--- /dev/null
+++ b/config/bootstrap-ubsan.mk
@@ -0,0 +1,7 @@ 
+# This option enables -fsanitize=undefined for stage2 and stage3.
+
+STAGE2_CFLAGS += -fsanitize=undefined
+STAGE3_CFLAGS += -fsanitize=undefined
+POSTSTAGE1_LDFLAGS += -fsanitize=undefined -static-libubsan -lpthread \
+		      -B$$r/prev-$(TARGET_SUBDIR)/libsanitizer/ubsan/ \
+		      -B$$r/prev-$(TARGET_SUBDIR)/libsanitizer/ubsan/.libs
diff --git a/gcc/ChangeLog.ubsan b/gcc/ChangeLog.ubsan
new file mode 100644
index 0000000..9ed8f96
--- /dev/null
+++ b/gcc/ChangeLog.ubsan
@@ -0,0 +1,189 @@ 
+2013-08-29  Marek Polacek  <polacek@redhat.com>
+
+	* Makefile.in (ubsan.o): Add $(HASHTAB_H) and gt-ubsan.h
+	dependencies.  Remove pointer-set.h dependency.
+	* ubsan.c: Convert to C style hash table.
+
+2013-08-28  Marek Polacek  <polacek@redhat.com>
+
+	* ubsan.c: Use pointer_map<tree> instead of pointer_map_t.
+	(insert_decl_for_type): Adjust.
+	(lookup_decl_for_type): Likewise.
+
+2013-08-28  Marek Polacek  <polacek@redhat.com>
+
+	* Makefile.in (ubsan.o): Add pointer-set.h dependency.  Remove
+	alloc-pool.h and HASH_TABLE_H dependencies.
+
+2013-08-27  Marek Polacek  <polacek@redhat.com>
+
+	* ubsan.c: Use pointer map instead of hash table.
+
+2013-08-26  Marek Polacek  <polacek@redhat.com>
+
+	* tree.h (enum tree_index): Add TI_POINTER_SIZED_TYPE.
+	(pointer_sized_int_node): Define.
+	* tree.c (build_common_tree_nodes): Initialize
+	pointer_sized_int_node.
+	* ubsan.c (ubsan_encode_value): Use pointer_sized_int_node instead
+	calling uptr_type.
+	(uptr_type): Remove function.
+	* asan.c (asan_global_struct): Use pointer_sized_int_node instead
+	calling build_nonstandard_integer_type.
+	(initialize_sanitizer_builtins): Likewise.
+	(asan_finish_file): Likewise.
+
+2013-08-23  Marek Polacek  <polacek@redhat.com>
+
+	* ubsan.c (ubsan_typedesc_hasher::hash): Hash the TYPE_UID of the
+	type.
+	(ubsan_type_descriptor): Get TYPE_MAIN_VARIANT before initializing
+	the type descriptor.
+
+2013-08-20  Marek Polacek  <polacek@redhat.com>
+
+	* ubsan.c (is_ubsan_builtin_p): New function.
+	* ubsan.h: Declare it.
+
+2013-08-05  Marek Polacek  <polacek@redhat.com>
+
+	* ubsan.c (ubsan_source_location_type): Properly create
+	const char type using build_qualified_type.
+
+2013-07-31  Marek Polacek  <polacek@redhat.com>
+
+	* doc/invoke.texi: Improve documentation of -fsanitize=undefined.
+
+2013-07-30  Marek Polacek  <polacek@redhat.com>
+
+	* config/rs6000/rs6000.h (FRAME_GROWS_DOWNWARD): Use flag_sanitize
+	instead of flag_asan.
+
+2013-07-30  Marek Polacek  <polacek@redhat.com>
+
+	* ubsan.c (ubsan_source_location): Use build_constructor_va
+	instead of build_constructor.
+	(ubsan_type_descriptor): Likewise.
+
+2013-07-29  Marek Polacek  <polacek@redhat.com>
+
+	* common.opt (static-libubsan): New option.
+	* doc/invoke.texi: Document -static-libubsan.
+
+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 064e7c3..7396313 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1154,7 +1154,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
@@ -1383,6 +1383,7 @@  OBJS = \
 	tree-affine.o \
 	asan.o \
 	tsan.o \
+	ubsan.o \
 	tree-call-cdce.o \
 	tree-cfg.o \
 	tree-cfgcleanup.o \
@@ -2028,6 +2029,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) \
@@ -2265,8 +2270,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) $(CGRAPH_H) $(HASHTAB_H) gt-ubsan.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) \
@@ -2836,7 +2844,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 \
@@ -3830,6 +3838,7 @@  GTFILES = $(CPP_ID_DATA_H) $(srcdir)/input.h $(srcdir)/coretypes.h \
   $(srcdir)/ipa-inline.h \
   $(srcdir)/vtable-verify.c \
   $(srcdir)/asan.c \
+  $(srcdir)/ubsan.c \
   $(srcdir)/tsan.c $(srcdir)/ipa-devirt.c \
   @all_gtfiles@
 
diff --git a/gcc/asan.c b/gcc/asan.c
index 81118a7..e7b1f47 100644
--- a/gcc/asan.c
+++ b/gcc/asan.c
@@ -1938,7 +1938,7 @@  asan_global_struct (void)
 	= build_decl (UNKNOWN_LOCATION, FIELD_DECL,
 		      get_identifier (field_names[i]),
 		      (i == 0 || i == 3) ? const_ptr_type_node
-		      : build_nonstandard_integer_type (POINTER_SIZE, 1));
+		      : pointer_sized_int_node);
       DECL_CONTEXT (fields[i]) = ret;
       if (i)
 	DECL_CHAIN (fields[i - 1]) = fields[i];
@@ -2016,10 +2016,12 @@  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,
-								1), NULL_TREE);
+				pointer_sized_int_node, NULL_TREE);
   tree BT_FN_VOID_INT
     = build_function_type_list (void_type_node, integer_type_node, NULL_TREE);
   tree BT_FN_BOOL_VPTR_PTR_IX_INT_INT[5];
@@ -2081,6 +2083,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,		\
@@ -2157,7 +2165,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);
@@ -2170,7 +2178,6 @@  asan_finish_file (void)
   if (gcount)
     {
       tree type = asan_global_struct (), var, ctor;
-      tree uptr = build_nonstandard_integer_type (POINTER_SIZE, 1);
       tree dtor_statements = NULL_TREE;
       vec<constructor_elt, va_gc> *v;
       char buf[20];
@@ -2199,22 +2206,23 @@  asan_finish_file (void)
       varpool_assemble_decl (varpool_node_for_decl (var));
 
       fn = builtin_decl_implicit (BUILT_IN_ASAN_REGISTER_GLOBALS);
+      tree gcount_tree = build_int_cst (pointer_sized_int_node, gcount);
       append_to_statement_list (build_call_expr (fn, 2,
 						 build_fold_addr_expr (var),
-						 build_int_cst (uptr, gcount)),
+						 gcount_tree),
 				&asan_ctor_statements);
 
       fn = builtin_decl_implicit (BUILT_IN_ASAN_UNREGISTER_GLOBALS);
       append_to_statement_list (build_call_expr (fn, 2,
 						 build_fold_addr_expr (var),
-						 build_int_cst (uptr, gcount)),
+						 gcount_tree),
 				&dtor_statements);
       cgraph_build_static_cdtor ('D', dtor_statements,
 				 MAX_RESERVED_INIT_PRIORITY - 1);
     }
   cgraph_build_static_cdtor ('I', asan_ctor_statements,
 			     MAX_RESERVED_INIT_PRIORITY - 1);
-  flag_asan = 1;
+  flag_sanitize |= SANITIZE_ADDRESS;
 }
 
 /* Instrument the current function.  */
@@ -2231,7 +2239,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 d8baad1..92aec31 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
@@ -10303,6 +10304,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 ce04049..8ccf3ae 100644
--- a/gcc/builtins.def
+++ b/gcc/builtins.def
@@ -161,7 +161,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..450c4eb
--- /dev/null
+++ b/gcc/c-family/ChangeLog.ubsan
@@ -0,0 +1,63 @@ 
+2013-08-15  Marek Polacek  <polacek@redhat.com>
+
+	* c-ubsan.c (ubsan_instrument_division): Evaluate SAVE_EXPRs
+	before the condition.
+	(ubsan_instrument_shift): Likewise.
+
+2013-08-14  Marek Polacek  <polacek@redhat.com>
+
+	* c-ubsan.c (ubsan_instrument_division): Use TYPE_MAIN_VARIANT
+	in the assert.
+
+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..9f43f6d
--- /dev/null
+++ b/gcc/c-family/c-ubsan.c
@@ -0,0 +1,158 @@ 
+/* 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.
+     Use TYPE_MAIN_VARIANT since typedefs can confuse us.  */
+  gcc_assert (TYPE_MAIN_VARIANT (TREE_TYPE (op0))
+	      == TYPE_MAIN_VARIANT (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);
+    }
+
+  /* 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);
+  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);
+    }
+
+  /* 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);
+
+  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..f41ae90
--- /dev/null
+++ b/gcc/c/ChangeLog.ubsan
@@ -0,0 +1,19 @@ 
+2013-07-31  Marek Polacek  <polacek@redhat.com>
+
+	* c-typeck.c (build_binary_op): Sanitize only when
+	doing shift or division.
+
+2013-07-30  Marek Polacek  <polacek@redhat.com>
+
+	* c-typeck.c (build_binary_op): Sanitize only when
+	current_function_decl is not zero.
+
+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 8b3e3d9..f29ca04 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.  */
@@ -9541,6 +9542,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;
 
@@ -9742,6 +9752,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
@@ -9789,6 +9800,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
@@ -9887,6 +9899,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)
@@ -9939,6 +9952,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)
@@ -10483,6 +10497,21 @@  build_binary_op (location_t location, enum tree_code code,
 	return error_mark_node;
     }
 
+  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);
+      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
@@ -10506,6 +10535,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 f4f58cb..d918b4a 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 a7d9170..4da5e7e 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 9082280..caf624f 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
@@ -2604,6 +2604,9 @@  Driver
 static-libtsan
 Driver
 
+static-libubsan
+Driver
+
 symbolic
 Driver
 
diff --git a/gcc/config/arm/linux-eabi.h b/gcc/config/arm/linux-eabi.h
index c6e686b..232c38d 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 d87cd8e..9d04472 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/config/rs6000/rs6000.h b/gcc/config/rs6000/rs6000.h
index e5a6abd..f89b20d 100644
--- a/gcc/config/rs6000/rs6000.h
+++ b/gcc/config/rs6000/rs6000.h
@@ -1498,7 +1498,8 @@  extern enum reg_class rs6000_constraints[RS6000_CONSTRAINT_MAX];
 
    On the RS/6000, we grow upwards, from the area after the outgoing
    arguments.  */
-#define FRAME_GROWS_DOWNWARD (flag_stack_protect != 0 || flag_asan != 0)
+#define FRAME_GROWS_DOWNWARD (flag_stack_protect != 0			\
+			      || (flag_sanitize & SANITIZE_ADDRESS) != 0)
 
 /* Size of the outgoing register save area */
 #define RS6000_REG_SAVE ((DEFAULT_ABI == ABI_AIX			\
diff --git a/gcc/cp/ChangeLog.ubsan b/gcc/cp/ChangeLog.ubsan
new file mode 100644
index 0000000..5674fc0
--- /dev/null
+++ b/gcc/cp/ChangeLog.ubsan
@@ -0,0 +1,13 @@ 
+2013-08-20  Marek Polacek  <polacek@redhat.com>
+
+	* error.c (dump_expr): Special-case ubsan builtins.
+
+2013-07-30  Marek Polacek  <polacek@redhat.com>
+
+	* typeck.c (cp_build_binary_op): Sanitize only when
+	current_function_decl is not zero.
+
+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/error.c b/gcc/cp/error.c
index af71000..db481a1 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"
 
 #include <new>                    // For placement-new.
 
@@ -2007,6 +2008,12 @@  dump_expr (cxx_pretty_printer *pp, 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 (pp, fn, flags | TFF_EXPR_IN_PARENS);
 	dump_call_expr_args (pp, t, flags, skipfirst);
       }
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index e09c325..b4abbc5 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)
@@ -4086,8 +4097,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)));
@@ -4125,8 +4140,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
@@ -4180,6 +4198,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))
@@ -4227,6 +4246,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))
@@ -4796,8 +4816,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);
 	}
 
@@ -4863,6 +4884,36 @@  cp_build_binary_op (location_t location,
   if (build_type == NULL_TREE)
     build_type = result_type;
 
+  if ((flag_sanitize & SANITIZE_UNDEFINED)
+      && !processing_template_decl
+      && current_function_decl != 0
+      && (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)
@@ -4873,6 +4924,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 0858f2f..1365f65 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -455,7 +455,7 @@  Objective-C and Objective-C++ Dialects}.
 @gccoptlist{@var{object-file-name}  -l@var{library} @gol
 -nostartfiles  -nodefaultlibs  -nostdlib -pie -rdynamic @gol
 -s  -static -static-libgcc -static-libstdc++ @gol
--static-libasan -static-libtsan @gol
+-static-libasan -static-libtsan -static-libubsan @gol
 -shared -shared-libgcc  -symbolic @gol
 -T @var{script}  -Wl,@var{option}  -Xlinker @var{option} @gol
 -u @var{symbol}}
@@ -5208,6 +5208,14 @@  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
+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
 Dump the final internal representation (RTL) to @var{file}.  If the
@@ -10160,6 +10168,15 @@  option is not used, then this links against the shared version of
 driver to link @file{libtsan} statically, without necessarily linking
 other libraries statically.
 
+@item -static-libubsan
+When the @option{-fsanitize=undefined} option is used to link a program,
+the GCC driver automatically links against @option{libubsan}.  If
+@file{libubsan} is available as a shared library, and the @option{-static}
+option is not used, then this links against the shared version of
+@file{libubsan}.  The @option{-static-libubsan} option directs the GCC
+driver to link @file{libubsan} statically, without necessarily linking
+other libraries statically.
+
 @item -static-libstdc++
 When the @command{g++} program is used to link a C++ program, it
 normally automatically links against @option{libstdc++}.  If
diff --git a/gcc/flag-types.h b/gcc/flag-types.h
index 8eea9a6..45616bc 100644
--- a/gcc/flag-types.h
+++ b/gcc/flag-types.h
@@ -191,6 +191,19 @@  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
+};
+
 /* flag_vtable_verify initialization levels. */
 enum vtv_priority {
   VTV_NO_PRIORITY       = 0,  /* i.E. Do NOT do vtable verification. */
diff --git a/gcc/gcc.c b/gcc/gcc.c
index 7c15cf3..d48c4db 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
 
 /*  This is the spec to use, once the code for creating the vtable
@@ -1333,6 +1362,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 },
@@ -5283,7 +5313,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;
@@ -5519,10 +5549,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;
@@ -5568,6 +5601,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);
@@ -5711,19 +5746,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)
@@ -5748,7 +5792,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
@@ -5773,7 +5817,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);
@@ -8070,6 +8116,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..9ba895e
--- /dev/null
+++ b/gcc/testsuite/ChangeLog.ubsan
@@ -0,0 +1,56 @@ 
+2013-08-20  Marek Polacek  <polacek@redhat.com>
+
+	* g++.dg/ubsan/div-by-zero-1.C: New test.
+
+2013-08-15  Marek Polacek  <polacek@redhat.com>
+
+	* 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.
+
+2013-08-14  Marek Polacek  <polacek@redhat.com>
+
+	* c-c++-common/ubsan/typedef-1.c: New test.
+
+2013-08-05  Marek Polacek  <polacek@redhat.com>
+
+	* c-c++-common/ubsan/const-char-1.c: New test.
+
+2013-07-31  Marek Polacek  <polacek@redhat.com>
+
+	* g++.dg/dg.exp: Add missing ubsan tests.
+
+2013-07-30  Marek Polacek  <polacek@redhat.com>
+
+	* c-c++-common/ubsan/const-expr.c: New test.
+
+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/const-char-1.c b/gcc/testsuite/c-c++-common/ubsan/const-char-1.c
new file mode 100644
index 0000000..6c2c3f8
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/ubsan/const-char-1.c
@@ -0,0 +1,9 @@ 
+/* { dg-do compile } */
+/* { dg-options "-fsanitize=shift" } */
+
+void
+foo (void)
+{
+  int y = 1 << 2;
+  __builtin_printf ("%d\n", y);
+}
diff --git a/gcc/testsuite/c-c++-common/ubsan/const-expr-1.c b/gcc/testsuite/c-c++-common/ubsan/const-expr-1.c
new file mode 100644
index 0000000..f474ec6
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/ubsan/const-expr-1.c
@@ -0,0 +1,22 @@ 
+/* { dg-do compile } */
+/* { dg-options "-fsanitize=shift -w" } */
+
+enum e { A = 1 << 1, B, };
+const int arr[] = {
+  1 << 2,
+  1 << 3,
+};
+
+int
+bar (int a, int b)
+{
+  return a >> b;
+}
+
+int
+foo (void)
+{
+  int i = 1;
+  int vla[B << 3];
+  return bar (A, (i <<= 6, i + 2));
+}
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/save-expr-1.c b/gcc/testsuite/c-c++-common/ubsan/save-expr-1.c
new file mode 100644
index 0000000..24532e8
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/ubsan/save-expr-1.c
@@ -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;
+}
diff --git a/gcc/testsuite/c-c++-common/ubsan/save-expr-2.c b/gcc/testsuite/c-c++-common/ubsan/save-expr-2.c
new file mode 100644
index 0000000..14ac17d
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/ubsan/save-expr-2.c
@@ -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;
+}
diff --git a/gcc/testsuite/c-c++-common/ubsan/save-expr-3.c b/gcc/testsuite/c-c++-common/ubsan/save-expr-3.c
new file mode 100644
index 0000000..dd2903b
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/ubsan/save-expr-3.c
@@ -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;
+}
diff --git a/gcc/testsuite/c-c++-common/ubsan/save-expr-4.c b/gcc/testsuite/c-c++-common/ubsan/save-expr-4.c
new file mode 100644
index 0000000..aa34a70
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/ubsan/save-expr-4.c
@@ -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);
+}
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/typedef-1.c b/gcc/testsuite/c-c++-common/ubsan/typedef-1.c
new file mode 100644
index 0000000..8dcf451
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/ubsan/typedef-1.c
@@ -0,0 +1,12 @@ 
+/* { dg-do compile } */
+/* { dg-options "-fsanitize=undefined" } */
+
+typedef int V;
+int
+foo (void)
+{
+  V v = 9;
+  int a = 3;
+  v += v % a;
+  return v / 3;
+}
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/dg.exp b/gcc/testsuite/g++.dg/dg.exp
index 710218e..0528538 100644
--- a/gcc/testsuite/g++.dg/dg.exp
+++ b/gcc/testsuite/g++.dg/dg.exp
@@ -52,6 +52,7 @@  set tests [prune $tests $srcdir/$subdir/tm/*]
 set tests [prune $tests $srcdir/$subdir/guality/*]
 set tests [prune $tests $srcdir/$subdir/simulate-thread/*]
 set tests [prune $tests $srcdir/$subdir/asan/*]
+set tests [prune $tests $srcdir/$subdir/ubsan/*]
 
 # Main loop.
 g++-dg-runtest $tests $DEFAULT_CXXFLAGS
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/div-by-zero-1.C b/gcc/testsuite/g++.dg/ubsan/div-by-zero-1.C
new file mode 100644
index 0000000..d7d2c8f1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ubsan/div-by-zero-1.C
@@ -0,0 +1,10 @@ 
+/* { dg-do compile } */
+/* { dg-options "-fsanitize=shift -w" } */
+
+void
+foo (int i)
+{
+  switch (i)
+  case 0 * (1 / 0): /* { dg-error "is not a constant expression" } */
+    ;
+}
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 53f53fd..4d12bc9 100644
--- a/gcc/toplev.c
+++ b/gcc/toplev.c
@@ -573,10 +573,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 ();
@@ -1542,12 +1542,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/tree.c b/gcc/tree.c
index 5ed0d1d..b469b97 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -9677,6 +9677,8 @@  build_common_tree_nodes (bool signed_char, bool short_double)
     = build_pointer_type (build_type_variant (void_type_node, 1, 0));
   fileptr_type_node = ptr_type_node;
 
+  pointer_sized_int_node = build_nonstandard_integer_type (POINTER_SIZE, 1);
+
   float_type_node = make_node (REAL_TYPE);
   TYPE_PRECISION (float_type_node) = FLOAT_TYPE_SIZE;
   layout_type (float_type_node);
diff --git a/gcc/tree.h b/gcc/tree.h
index 501448a..83edaba 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -4288,6 +4288,7 @@  enum tree_index
   TI_VA_LIST_FPR_COUNTER_FIELD,
   TI_BOOLEAN_TYPE,
   TI_FILEPTR_TYPE,
+  TI_POINTER_SIZED_TYPE,
 
   TI_DFLOAT32_TYPE,
   TI_DFLOAT64_TYPE,
@@ -4444,6 +4445,7 @@  extern GTY(()) tree global_trees[TI_MAX];
 #define va_list_fpr_counter_field	global_trees[TI_VA_LIST_FPR_COUNTER_FIELD]
 /* The C type `FILE *'.  */
 #define fileptr_type_node		global_trees[TI_FILEPTR_TYPE]
+#define pointer_sized_int_node		global_trees[TI_POINTER_SIZED_TYPE]
 
 #define boolean_type_node		global_trees[TI_BOOLEAN_TYPE]
 #define boolean_false_node		global_trees[TI_BOOLEAN_FALSE]
diff --git a/gcc/tsan.c b/gcc/tsan.c
index b9171c8..fb91129 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.  */
@@ -775,7 +775,7 @@  make_pass_tsan (gcc::context *ctxt)
 static bool
 tsan_gate_O0 (void)
 {
-  return flag_tsan != 0 && !optimize;
+  return (flag_sanitize & SANITIZE_THREAD) != 0 && !optimize;
 }
 
 namespace {
diff --git a/gcc/ubsan.c b/gcc/ubsan.c
new file mode 100644
index 0000000..e4bdd2a
--- /dev/null
+++ b/gcc/ubsan.c
@@ -0,0 +1,416 @@ 
+/* 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 "cgraph.h"
+#include "gimple.h"
+#include "hashtab.h"
+#include "pointer-set.h"
+#include "output.h"
+#include "toplev.h"
+#include "ubsan.h"
+#include "c-family/c-common.h"
+
+/* Map from a tree to a VAR_DECL tree.  */
+
+struct GTY(()) tree_type_map {
+  struct tree_map_base type;
+  tree decl;
+};
+
+#define tree_type_map_eq tree_map_base_eq
+#define tree_type_map_hash tree_map_base_hash
+#define tree_type_map_marked_p tree_map_base_marked_p
+
+static GTY ((if_marked ("tree_type_map_marked_p"), param_is (struct tree_type_map)))
+     htab_t decl_tree_for_type;
+
+/* Lookup a VAR_DECL for TYPE, and return it if we find one.  */
+
+static tree
+decl_for_type_lookup (tree type)
+{
+  /* If the hash table is not initialized yet, create it now.  */
+  if (decl_tree_for_type == NULL)
+    {
+      decl_tree_for_type = htab_create_ggc (10, tree_type_map_hash,
+					    tree_type_map_eq, 0);
+      /* That also means we don't have to bother with the lookup.  */
+      return NULL_TREE;
+    }
+
+  struct tree_type_map *h, in;
+  in.type.from = type;
+
+  h = (struct tree_type_map *)
+      htab_find_with_hash (decl_tree_for_type, &in, TYPE_UID (type));
+  return h ? h->decl : NULL_TREE;
+}
+
+/* Insert a mapping TYPE->DECL in the VAR_DECL for type hashtable.  */
+
+static void
+decl_for_type_insert (tree type, tree decl)
+{
+  struct tree_type_map *h;
+  void **slot;
+
+  h = ggc_alloc_tree_type_map ();
+  h->type.from = type;
+  h->decl = decl;
+  slot = htab_find_slot_with_hash (decl_tree_for_type, h, TYPE_UID (type),
+                                  INSERT);
+  *(struct tree_type_map **) slot = h;
+}
+
+/* Helper routine, which encodes a value in the pointer_sized_int_node.
+   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, pointer_sized_int_node, 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 (pointer_sized_int_node, 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 = build_qualified_type (char_type_node,
+					       TYPE_QUAL_CONST);
+
+  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 ();
+
+  xloc = expand_location (loc);
+
+  /* Fill in the values from LOC.  */
+  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);
+  tree ctor = build_constructor_va (type, 3, NULL_TREE, str, NULL_TREE,
+				    build_int_cst (unsigned_type_node,
+						   xloc.line), 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 pointer map; if not found,
+   create the VAR_DECL, put it into the pointer map and return the
+   ADDR_EXPR of it.  TYPE describes a particular type.  */
+
+tree
+ubsan_type_descriptor (tree type)
+{
+  /* See through any typedefs.  */
+  type = TYPE_MAIN_VARIANT (type);
+
+  tree decl = decl_for_type_lookup (type);
+  if (decl != NULL_TREE)
+    return decl;
+
+  tree dtype = ubsan_type_descriptor_type ();
+  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++);
+  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;
+
+  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;
+  tree ctor = build_constructor_va (dtype, 3, NULL_TREE,
+				    build_int_cst (short_unsigned_type_node,
+						   tkind), NULL_TREE,
+				    build_int_cst (short_unsigned_type_node,
+						   tinfo), 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 pointer map.  */
+  decl = build_fold_addr_expr (decl);
+  decl_for_type_insert (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));
+}
+
+/* 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;
+}
+
+#include "gt-ubsan.h"
diff --git a/gcc/ubsan.h b/gcc/ubsan.h
new file mode 100644
index 0000000..3553a6c
--- /dev/null
+++ b/gcc/ubsan.h
@@ -0,0 +1,31 @@ 
+/* 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);
+extern bool is_ubsan_builtin_p (tree);
+
+#endif  /* GCC_UBSAN_H  */
+
diff --git a/gcc/varasm.c b/gcc/varasm.c
index 69ec26a..0504eeb 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;
@@ -3376,7 +3377,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;
@@ -6291,7 +6293,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
@@ -6317,7 +6320,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).  */
@@ -7075,7 +7079,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);
@@ -7085,7 +7089,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,
@@ -7235,7 +7240,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)))
 	    {
@@ -7251,7 +7256,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);
diff --git a/libsanitizer/ChangeLog b/libsanitizer/ChangeLog
index d2c80b3..318a5c7 100644
--- a/libsanitizer/ChangeLog
+++ b/libsanitizer/ChangeLog
@@ -1,3 +1,13 @@ 
+2013-07-05  Jakub Jelinek  <jakub@redhat.com>
+
+	* Makefile.am (SUBDIRS): Add ubsan.
+	* configure.ac (AC_CONFIG_FILES): Add ubsan/Makefile.
+	* merge.sh: Merge ubsan.
+	* sanitizer_common/sanitizer_report_decorator.h: Partial merge from trunk.
+	* sanitizer_common/sanitizer_printf.cc: Likewise.
+	* sanitizer_common/sanitizer_common.h: Likewise.
+	* ubsan: New directory. Import ubsan runtime from llvm.
+
 2013-06-03  Christophe Lyon  <christophe.lyon@linaro.org>
 
 	* sanitizer_common/sanitizer_linux.cc (MemoryMappingLayout::Next):
diff --git a/libsanitizer/Makefile.am b/libsanitizer/Makefile.am
index 308d438..739c33b 100644
--- a/libsanitizer/Makefile.am
+++ b/libsanitizer/Makefile.am
@@ -1,13 +1,13 @@ 
 ACLOCAL_AMFLAGS = -I .. -I ../config
 
 if TSAN_SUPPORTED
-SUBDIRS = interception sanitizer_common asan tsan 
+SUBDIRS = interception sanitizer_common asan tsan ubsan
 else
-SUBDIRS = interception sanitizer_common asan 
+SUBDIRS = interception sanitizer_common asan ubsan
 endif
 
 if USING_MAC_INTERPOSE
-SUBDIRS = sanitizer_common asan
+SUBDIRS = sanitizer_common asan ubsan
 endif
 
 # Work around what appears to be a GNU make bug handling MAKEFLAGS
diff --git a/libsanitizer/Makefile.in b/libsanitizer/Makefile.in
index 125692e..286cea6 100644
--- a/libsanitizer/Makefile.in
+++ b/libsanitizer/Makefile.in
@@ -76,7 +76,7 @@  AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \
 	$(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS
 ETAGS = etags
 CTAGS = ctags
-DIST_SUBDIRS = interception sanitizer_common asan tsan
+DIST_SUBDIRS = interception sanitizer_common asan ubsan tsan
 ACLOCAL = @ACLOCAL@
 AMTAR = @AMTAR@
 AR = @AR@
@@ -209,9 +209,9 @@  top_build_prefix = @top_build_prefix@
 top_builddir = @top_builddir@
 top_srcdir = @top_srcdir@
 ACLOCAL_AMFLAGS = -I .. -I ../config
-@TSAN_SUPPORTED_FALSE@SUBDIRS = interception sanitizer_common asan 
-@TSAN_SUPPORTED_TRUE@SUBDIRS = interception sanitizer_common asan tsan 
-@USING_MAC_INTERPOSE_TRUE@SUBDIRS = sanitizer_common asan
+@TSAN_SUPPORTED_FALSE@SUBDIRS = interception sanitizer_common asan ubsan
+@TSAN_SUPPORTED_TRUE@SUBDIRS = interception sanitizer_common asan tsan ubsan
+@USING_MAC_INTERPOSE_TRUE@SUBDIRS = sanitizer_common asan ubsan
 
 # Work around what appears to be a GNU make bug handling MAKEFLAGS
 # values defined in terms of make variables, as is the case for CC and
diff --git a/libsanitizer/configure b/libsanitizer/configure
index 19a1037..2cad869 100755
--- a/libsanitizer/configure
+++ b/libsanitizer/configure
@@ -14543,7 +14543,7 @@  fi
 ac_config_files="$ac_config_files Makefile"
 
 
-ac_config_files="$ac_config_files interception/Makefile sanitizer_common/Makefile asan/Makefile"
+ac_config_files="$ac_config_files interception/Makefile sanitizer_common/Makefile asan/Makefile ubsan/Makefile"
 
 
 if test "x$TSAN_SUPPORTED" = "xyes"; then
@@ -15674,6 +15674,7 @@  do
     "interception/Makefile") CONFIG_FILES="$CONFIG_FILES interception/Makefile" ;;
     "sanitizer_common/Makefile") CONFIG_FILES="$CONFIG_FILES sanitizer_common/Makefile" ;;
     "asan/Makefile") CONFIG_FILES="$CONFIG_FILES asan/Makefile" ;;
+    "ubsan/Makefile") CONFIG_FILES="$CONFIG_FILES ubsan/Makefile" ;;
     "tsan/Makefile") CONFIG_FILES="$CONFIG_FILES tsan/Makefile" ;;
 
   *) as_fn_error "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
@@ -17039,6 +17040,17 @@  _EOF
    . ${multi_basedir}/config-ml.in
    { ml_norecursion=; unset ml_norecursion;}
  ;;
+    "ubsan/Makefile":F) cat > vpsed$$ << \_EOF
+s!`test -f '$<' || echo '$(srcdir)/'`!!
+_EOF
+   sed -f vpsed$$ $ac_file > tmp$$
+   mv tmp$$ $ac_file
+   rm vpsed$$
+   echo 'MULTISUBDIR =' >> $ac_file
+   ml_norecursion=yes
+   . ${multi_basedir}/config-ml.in
+   { ml_norecursion=; unset ml_norecursion;}
+ ;;
     "tsan/Makefile":F) cat > vpsed$$ << \_EOF
 s!`test -f '$<' || echo '$(srcdir)/'`!!
 _EOF
diff --git a/libsanitizer/configure.ac b/libsanitizer/configure.ac
index 3cf161d..5919da6 100644
--- a/libsanitizer/configure.ac
+++ b/libsanitizer/configure.ac
@@ -89,7 +89,7 @@  AM_CONDITIONAL(USING_MAC_INTERPOSE, $MAC_INTERPOSE)
 
 AC_CONFIG_FILES([Makefile])
 
-AC_CONFIG_FILES(AC_FOREACH([DIR], [interception sanitizer_common asan], [DIR/Makefile ]),
+AC_CONFIG_FILES(AC_FOREACH([DIR], [interception sanitizer_common asan ubsan], [DIR/Makefile ]),
   [cat > vpsed$$ << \_EOF
 s!`test -f '$<' || echo '$(srcdir)/'`!!
 _EOF
diff --git a/libsanitizer/merge.sh b/libsanitizer/merge.sh
index 9c29b31..23748a7 100755
--- a/libsanitizer/merge.sh
+++ b/libsanitizer/merge.sh
@@ -69,6 +69,7 @@  merge lib/asan asan
 merge lib/tsan/rtl tsan
 merge lib/sanitizer_common sanitizer_common
 merge lib/interception interception
+merge lib/ubsan ubsan
 
 rm -rf upstream