diff mbox

Convert asan to use sanitizer.def builtins, initialize them if the FE didn't

Message ID 20121122151346.GS2315@tucnak.redhat.com
State New
Headers show

Commit Message

Jakub Jelinek Nov. 22, 2012, 3:13 p.m. UTC
On Thu, Nov 22, 2012 at 09:08:23AM +0100, Jakub Jelinek wrote:
> On Thu, Nov 22, 2012 at 11:29:05AM +0400, Dmitry Vyukov wrote:
> > +static bool
> > +tsan_gate (void)
> > +{
> > +  return flag_tsan != 0
> > +	 && builtin_decl_implicit_p (BUILT_IN_TSAN_INIT);
> > 
> > 
> > What does it mean? Why builtin_decl_implicit_p (BUILT_IN_TSAN_INIT)?
> 
> It is a temporary workaround, I'll handle it when the patch goes in.
> The thing is that while the C/C++ family of FEs will create all the builtins
> just because they are included in builtins.def, other FEs won't.
> So we need some routine that will build the builtins if the FEs didn't
> initialize them.

Like so.  The c-family/ FEs (C/ObjC/C++/ObjC++) will initialize the builtins
themselves automatically, for other FEs that don't there is a new routine
that initializes them the first time they are needed.

Ok for trunk (the patch is on top of the tsan patch)?

2012-11-22  Jakub Jelinek  <jakub@redhat.com>

	* sanitizer.def: Add Address Sanitizer builtins.
	Rename BUILT_IN_TSAN_READ_* to BUILT_IN_TSAN_READ* and
	BUILT_IN_TSAN_WRITE_* to BUILT_IN_TSAN_WRITE*.
	* Makefile.in (asan.o): Depend on langhooks.h.
	(tsan.o): Depend on asan.h.
	* asan.h (initialize_sanitizer_builtins): New prototype.
	* asan.c: Include langhooks.h.
	(report_error_func): Use builtin_decl_implicit of corresponding
	BUILT_IN_ASAN_REPORT_{LOAD,STORE}*.
	(asan_init_func): Removed.
	(initialize_sanitizer_builtins): New function.
	(asan_finish_file): Call it.  Use builtin_decl_implicit
	on BUILT_IN_ASAN_{INIT,{,UN}REGISTER_GLOBALS}.
	(asan_instrument): Call initialize_sanitizer_builtins.
	* builtins.def (DEF_SANITIZER_BUILTIN): Change condition to
	(flag_asan || flag_tsan).
	* tsan.c: Include asan.h and tsan.h.
	(get_memory_access_decl): Rename BUILT_IN_TSAN_{READ,WRITE}_*
	to BUILT_IN_TSAN_{READ,WRITE}*.
	(tsan_pass): Call initialize_sanitizer_builtins.
	(tsan_gate, tsan_gate_O0): Don't check if
	builtin_decl_implicit_p (BUILT_IN_TSAN_INIT) is true.
	(tsan_finish_file): Call initialize_sanitizer_builtins.
	* builtin-types.def (BT_FN_VOID_PTR_PTRMODE): New fn type.



	Jakub

Comments

Dodji Seketeli Dec. 3, 2012, 4:58 p.m. UTC | #1
Jakub Jelinek <jakub@redhat.com> writes:

> Ok for trunk (the patch is on top of the tsan patch)?
>
> 2012-11-22  Jakub Jelinek  <jakub@redhat.com>
>
> 	* sanitizer.def: Add Address Sanitizer builtins.
> 	Rename BUILT_IN_TSAN_READ_* to BUILT_IN_TSAN_READ* and
> 	BUILT_IN_TSAN_WRITE_* to BUILT_IN_TSAN_WRITE*.
> 	* Makefile.in (asan.o): Depend on langhooks.h.
> 	(tsan.o): Depend on asan.h.
> 	* asan.h (initialize_sanitizer_builtins): New prototype.
> 	* asan.c: Include langhooks.h.
> 	(report_error_func): Use builtin_decl_implicit of corresponding
> 	BUILT_IN_ASAN_REPORT_{LOAD,STORE}*.
> 	(asan_init_func): Removed.
> 	(initialize_sanitizer_builtins): New function.
> 	(asan_finish_file): Call it.  Use builtin_decl_implicit
> 	on BUILT_IN_ASAN_{INIT,{,UN}REGISTER_GLOBALS}.
> 	(asan_instrument): Call initialize_sanitizer_builtins.
> 	* builtins.def (DEF_SANITIZER_BUILTIN): Change condition to
> 	(flag_asan || flag_tsan).
> 	* tsan.c: Include asan.h and tsan.h.
> 	(get_memory_access_decl): Rename BUILT_IN_TSAN_{READ,WRITE}_*
> 	to BUILT_IN_TSAN_{READ,WRITE}*.
> 	(tsan_pass): Call initialize_sanitizer_builtins.
> 	(tsan_gate, tsan_gate_O0): Don't check if
> 	builtin_decl_implicit_p (BUILT_IN_TSAN_INIT) is true.
> 	(tsan_finish_file): Call initialize_sanitizer_builtins.
> 	* builtin-types.def (BT_FN_VOID_PTR_PTRMODE): New fn type.
>
> --- gcc/sanitizer.def.jj	2012-11-22 13:17:24.000000000 +0100
> +++ gcc/sanitizer.def	2012-11-22 15:45:55.873655417 +0100
> @@ -1,3 +1,34 @@
> +/* Address Sanitizer */

Maybe we could use some introductory comment at the beginning of this
file, a bit like what we have for sync-builtins.def.  I think this kind
of comments are a great asset for people who are new to the file.

Otherwise, the asan parts of the patch looks OK to me.

Thanks.
diff mbox

Patch

--- gcc/sanitizer.def.jj	2012-11-22 13:17:24.000000000 +0100
+++ gcc/sanitizer.def	2012-11-22 15:45:55.873655417 +0100
@@ -1,3 +1,34 @@ 
+/* Address Sanitizer */
+DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_INIT, "__asan_init",
+		      BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_REPORT_LOAD1, "__asan_report_load1",
+		      BT_FN_VOID_PTR, ATTR_NORETURN_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_REPORT_LOAD2, "__asan_report_load2",
+		      BT_FN_VOID_PTR, ATTR_NORETURN_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_REPORT_LOAD4, "__asan_report_load4",
+		      BT_FN_VOID_PTR, ATTR_NORETURN_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_REPORT_LOAD8, "__asan_report_load8",
+		      BT_FN_VOID_PTR, ATTR_NORETURN_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_REPORT_LOAD16, "__asan_report_load16",
+		      BT_FN_VOID_PTR, ATTR_NORETURN_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_REPORT_STORE1, "__asan_report_store1",
+		      BT_FN_VOID_PTR, ATTR_NORETURN_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_REPORT_STORE2, "__asan_report_store2",
+		      BT_FN_VOID_PTR, ATTR_NORETURN_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_REPORT_STORE4, "__asan_report_store4",
+		      BT_FN_VOID_PTR, ATTR_NORETURN_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_REPORT_STORE8, "__asan_report_store8",
+		      BT_FN_VOID_PTR, ATTR_NORETURN_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_REPORT_STORE16, "__asan_report_store16",
+		      BT_FN_VOID_PTR, ATTR_NORETURN_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_REGISTER_GLOBALS,
+		      "__asan_register_globals",
+		      BT_FN_VOID_PTR_PTRMODE, ATTR_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_UNREGISTER_GLOBALS,
+		      "__asan_unregister_globals",
+		      BT_FN_VOID_PTR_PTRMODE, ATTR_NOTHROW_LEAF_LIST)
+
+/* Thread Sanitizer */
 DEF_SANITIZER_BUILTIN(BUILT_IN_TSAN_INIT, "__tsan_init", 
 		      BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST)
 DEF_SANITIZER_BUILTIN(BUILT_IN_TSAN_FUNC_ENTRY, "__tsan_func_entry",
@@ -6,23 +37,23 @@  DEF_SANITIZER_BUILTIN(BUILT_IN_TSAN_FUNC
 		      BT_FN_VOID_PTR, ATTR_NOTHROW_LEAF_LIST)
 DEF_SANITIZER_BUILTIN(BUILT_IN_TSAN_VPTR_UPDATE, "__tsan_vptr_update",
 		      BT_FN_VOID_PTR, ATTR_NOTHROW_LEAF_LIST)
-DEF_SANITIZER_BUILTIN(BUILT_IN_TSAN_READ_1, "__tsan_read1",
+DEF_SANITIZER_BUILTIN(BUILT_IN_TSAN_READ1, "__tsan_read1",
 		      BT_FN_VOID_PTR, ATTR_NOTHROW_LEAF_LIST)
-DEF_SANITIZER_BUILTIN(BUILT_IN_TSAN_READ_2, "__tsan_read2",
+DEF_SANITIZER_BUILTIN(BUILT_IN_TSAN_READ2, "__tsan_read2",
 		      BT_FN_VOID_PTR, ATTR_NOTHROW_LEAF_LIST)
-DEF_SANITIZER_BUILTIN(BUILT_IN_TSAN_READ_4, "__tsan_read4",
+DEF_SANITIZER_BUILTIN(BUILT_IN_TSAN_READ4, "__tsan_read4",
 		      BT_FN_VOID_PTR, ATTR_NOTHROW_LEAF_LIST)
-DEF_SANITIZER_BUILTIN(BUILT_IN_TSAN_READ_8, "__tsan_read8",
+DEF_SANITIZER_BUILTIN(BUILT_IN_TSAN_READ8, "__tsan_read8",
 		      BT_FN_VOID_PTR, ATTR_NOTHROW_LEAF_LIST)
-DEF_SANITIZER_BUILTIN(BUILT_IN_TSAN_READ_16, "__tsan_read16",
+DEF_SANITIZER_BUILTIN(BUILT_IN_TSAN_READ16, "__tsan_read16",
 		      BT_FN_VOID_PTR, ATTR_NOTHROW_LEAF_LIST)
-DEF_SANITIZER_BUILTIN(BUILT_IN_TSAN_WRITE_1, "__tsan_write1",
+DEF_SANITIZER_BUILTIN(BUILT_IN_TSAN_WRITE1, "__tsan_write1",
 		      BT_FN_VOID_PTR, ATTR_NOTHROW_LEAF_LIST)
-DEF_SANITIZER_BUILTIN(BUILT_IN_TSAN_WRITE_2, "__tsan_write2",
+DEF_SANITIZER_BUILTIN(BUILT_IN_TSAN_WRITE2, "__tsan_write2",
 		      BT_FN_VOID_PTR, ATTR_NOTHROW_LEAF_LIST)
-DEF_SANITIZER_BUILTIN(BUILT_IN_TSAN_WRITE_4, "__tsan_write4",
+DEF_SANITIZER_BUILTIN(BUILT_IN_TSAN_WRITE4, "__tsan_write4",
 		      BT_FN_VOID_PTR, ATTR_NOTHROW_LEAF_LIST)
-DEF_SANITIZER_BUILTIN(BUILT_IN_TSAN_WRITE_8, "__tsan_write8",
+DEF_SANITIZER_BUILTIN(BUILT_IN_TSAN_WRITE8, "__tsan_write8",
 		      BT_FN_VOID_PTR, ATTR_NOTHROW_LEAF_LIST)
-DEF_SANITIZER_BUILTIN(BUILT_IN_TSAN_WRITE_16, "__tsan_write16",
+DEF_SANITIZER_BUILTIN(BUILT_IN_TSAN_WRITE16, "__tsan_write16",
 		      BT_FN_VOID_PTR, ATTR_NOTHROW_LEAF_LIST)
--- gcc/Makefile.in.jj	2012-11-22 13:17:24.000000000 +0100
+++ gcc/Makefile.in	2012-11-22 15:41:09.700285758 +0100
@@ -2228,13 +2228,13 @@  stor-layout.o : stor-layout.c $(CONFIG_H
 asan.o : asan.c asan.h $(CONFIG_H) $(SYSTEM_H) $(GIMPLE_H) \
    output.h coretypes.h $(GIMPLE_PRETTY_PRINT_H) \
    tree-iterator.h $(TREE_FLOW_H) $(TREE_PASS_H) \
-   $(TARGET_H) $(EXPR_H) $(OPTABS_H) $(TM_P_H)
+   $(TARGET_H) $(EXPR_H) $(OPTABS_H) $(TM_P_H) langhooks.h
 tsan.o : $(CONFIG_H) $(SYSTEM_H) $(TREE_H) $(TREE_INLINE_H) \
    $(GIMPLE_H) $(DIAGNOSTIC_H) langhooks.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
+   intl.h cfghooks.h output.h options.h c-family/c-common.h tsan.h asan.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) \
--- gcc/asan.h.jj	2012-11-12 16:58:41.000000000 +0100
+++ gcc/asan.h	2012-11-22 15:13:10.590930008 +0100
@@ -24,6 +24,7 @@  along with GCC; see the file COPYING3.
 extern void asan_finish_file (void);
 extern rtx asan_emit_stack_protection (rtx, HOST_WIDE_INT *, tree *, int);
 extern bool asan_protect_global (tree);
+extern void initialize_sanitizer_builtins (void);
 
 /* Alias set for accessing the shadow memory.  */
 extern alias_set_type asan_shadow_set;
--- gcc/asan.c.jj	2012-11-22 11:35:47.000000000 +0100
+++ gcc/asan.c	2012-11-22 15:46:08.326588664 +0100
@@ -33,6 +33,7 @@  along with GCC; see the file COPYING3.
 #include "optabs.h"
 #include "output.h"
 #include "tm_p.h"
+#include "langhooks.h"
 
 /* AddressSanitizer finds out-of-bounds and use-after-free bugs
    with <2x slowdown on average.
@@ -485,38 +486,16 @@  asan_protect_global (tree decl)
 static tree
 report_error_func (bool is_store, int size_in_bytes)
 {
-  tree fn_type;
-  tree def;
-  char name[100];
-
-  sprintf (name, "__asan_report_%s%d",
-	   is_store ? "store" : "load", size_in_bytes);
-  fn_type = build_function_type_list (void_type_node, ptr_type_node, NULL_TREE);
-  def = build_fn_decl (name, fn_type);
-  TREE_NOTHROW (def) = 1;
-  DECL_IGNORED_P (def) = 1;
-  TREE_THIS_VOLATILE (def) = 1;  /* Attribute noreturn. Surprise!  */
-  DECL_ATTRIBUTES (def) = tree_cons (get_identifier ("leaf"),
-				     NULL, DECL_ATTRIBUTES (def));
-  return def;
+  static enum built_in_function report[2][5]
+    = { { BUILT_IN_ASAN_REPORT_LOAD1, BUILT_IN_ASAN_REPORT_LOAD2,
+	  BUILT_IN_ASAN_REPORT_LOAD4, BUILT_IN_ASAN_REPORT_LOAD8,
+	  BUILT_IN_ASAN_REPORT_LOAD16 },
+	{ BUILT_IN_ASAN_REPORT_STORE1, BUILT_IN_ASAN_REPORT_STORE2,
+	  BUILT_IN_ASAN_REPORT_STORE4, BUILT_IN_ASAN_REPORT_STORE8,
+	  BUILT_IN_ASAN_REPORT_STORE16 } };
+  return builtin_decl_implicit (report[is_store][exact_log2 (size_in_bytes)]);
 }
 
-/* Construct a function tree for __asan_init().  */
-
-static tree
-asan_init_func (void)
-{
-  tree fn_type;
-  tree def;
-
-  fn_type = build_function_type_list (void_type_node, NULL_TREE);
-  def = build_fn_decl ("__asan_init", fn_type);
-  TREE_NOTHROW (def) = 1;
-  DECL_IGNORED_P (def) = 1;
-  return def;
-}
-
-
 #define PROB_VERY_UNLIKELY	(REG_BR_PROB_BASE / 2000 - 1)
 #define PROB_ALWAYS		(REG_BR_PROB_BASE)
 
@@ -1489,6 +1468,38 @@  asan_add_global (tree decl, tree type, v
   CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, init);
 }
 
+/* Initialize sanitizer.def builtins if the FE hasn't initialized them.  */
+void
+initialize_sanitizer_builtins (void)
+{
+  tree decl;
+
+  if (builtin_decl_implicit (BUILT_IN_ASAN_INIT))
+    return;
+
+  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_PTRMODE
+    = build_function_type_list (void_type_node, ptr_type_node,
+				build_nonstandard_integer_type (POINTER_SIZE,
+								1), NULL_TREE);
+#undef ATTR_NOTHROW_LEAF_LIST
+#define ATTR_NOTHROW_LEAF_LIST ECF_NOTHROW | ECF_LEAF
+#undef ATTR_NORETURN_NOTHROW_LEAF_LIST
+#define ATTR_NORETURN_NOTHROW_LEAF_LIST ECF_NORETURN | ATTR_NOTHROW_LEAF_LIST
+#undef DEF_SANITIZER_BUILTIN
+#define DEF_SANITIZER_BUILTIN(ENUM, NAME, TYPE, ATTRS) \
+  decl = add_builtin_function ("__builtin_" NAME, TYPE, ENUM,		\
+			       BUILT_IN_NORMAL, NAME, NULL_TREE);	\
+  set_call_expr_flags (decl, ATTRS);					\
+  set_builtin_decl (ENUM, decl, true);
+
+#include "sanitizer.def"
+
+#undef DEF_SANITIZER_BUILTIN
+}
+
 /* Needs to be GTY(()), because cgraph_build_static_cdtor may
    invoke ggc_collect.  */
 static GTY(()) tree asan_ctor_statements;
@@ -1504,14 +1515,16 @@  asan_finish_file (void)
   struct varpool_node *vnode;
   unsigned HOST_WIDE_INT gcount = 0;
 
-  append_to_statement_list (build_call_expr (asan_init_func (), 0),
-			    &asan_ctor_statements);
+  initialize_sanitizer_builtins ();
+
+  tree fn = builtin_decl_implicit (BUILT_IN_ASAN_INIT);
+  append_to_statement_list (build_call_expr (fn, 0), &asan_ctor_statements);
   FOR_EACH_DEFINED_VARIABLE (vnode)
     if (asan_protect_global (vnode->symbol.decl))
       ++gcount;
   if (gcount)
     {
-      tree type = asan_global_struct (), var, ctor, decl;
+      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;
@@ -1535,20 +1548,14 @@  asan_finish_file (void)
       DECL_INITIAL (var) = ctor;
       varpool_assemble_decl (varpool_node_for_decl (var));
 
-      type = build_function_type_list (void_type_node, ptr_type_node,
-				       uptr, NULL_TREE);
-      decl = build_fn_decl ("__asan_register_globals", type);
-      TREE_NOTHROW (decl) = 1;
-      DECL_IGNORED_P (decl) = 1;
-      append_to_statement_list (build_call_expr (decl, 2,
+      fn = builtin_decl_implicit (BUILT_IN_ASAN_REGISTER_GLOBALS);
+      append_to_statement_list (build_call_expr (fn, 2,
 						 build_fold_addr_expr (var),
 						 build_int_cst (uptr, gcount)),
 				&asan_ctor_statements);
 
-      decl = build_fn_decl ("__asan_unregister_globals", type);
-      TREE_NOTHROW (decl) = 1;
-      DECL_IGNORED_P (decl) = 1;
-      append_to_statement_list (build_call_expr (decl, 2,
+      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)),
 				&dtor_statements);
@@ -1579,7 +1586,10 @@  static unsigned int
 asan_instrument (void)
 {
   if (shadow_ptr_types[0] == NULL_TREE)
-    asan_init_shadow_ptr_types ();
+    {
+      asan_init_shadow_ptr_types ();
+      initialize_sanitizer_builtins ();
+    }
   transform_statements ();
   return 0;
 }
--- gcc/builtins.def.jj	2012-11-22 13:17:24.000000000 +0100
+++ gcc/builtins.def	2012-11-22 15:00:04.630358678 +0100
@@ -156,7 +156,7 @@  along with GCC; see the file COPYING3.
 #define DEF_SANITIZER_BUILTIN(ENUM, NAME, TYPE, ATTRS) \
   DEF_BUILTIN (ENUM, "__builtin_" NAME, BUILT_IN_NORMAL, TYPE, TYPE,    \
 	       true, true, true, ATTRS, true, \
-	       flag_tsan)
+	       (flag_asan || flag_tsan))
 
 /* Define an attribute list for math functions that are normally
    "impure" because some of them may write into global memory for
--- gcc/tsan.c.jj	2012-11-22 13:17:24.000000000 +0100
+++ gcc/tsan.c	2012-11-22 15:39:38.080808225 +0100
@@ -37,6 +37,8 @@  along with GCC; see the file COPYING3.
 #include "target.h"
 #include "cgraph.h"
 #include "diagnostic.h"
+#include "tsan.h"
+#include "asan.h"
 
 /* Number of instrumented memory accesses in the current function.  */
 
@@ -49,20 +51,20 @@  get_memory_access_decl (bool is_write, u
   enum built_in_function fcode;
 
   if (size <= 1)
-    fcode = is_write ? BUILT_IN_TSAN_WRITE_1
-		     : BUILT_IN_TSAN_READ_1;
+    fcode = is_write ? BUILT_IN_TSAN_WRITE1
+		     : BUILT_IN_TSAN_READ1;
   else if (size <= 3)
-    fcode = is_write ? BUILT_IN_TSAN_WRITE_2
-		     : BUILT_IN_TSAN_READ_2;
+    fcode = is_write ? BUILT_IN_TSAN_WRITE2
+		     : BUILT_IN_TSAN_READ2;
   else if (size <= 7)
-    fcode = is_write ? BUILT_IN_TSAN_WRITE_4
-		     : BUILT_IN_TSAN_READ_4;
+    fcode = is_write ? BUILT_IN_TSAN_WRITE4
+		     : BUILT_IN_TSAN_READ4;
   else if (size <= 15)
-    fcode = is_write ? BUILT_IN_TSAN_WRITE_8
-		     : BUILT_IN_TSAN_READ_8;
+    fcode = is_write ? BUILT_IN_TSAN_WRITE8
+		     : BUILT_IN_TSAN_READ8;
   else
-    fcode = is_write ? BUILT_IN_TSAN_WRITE_16
-		     : BUILT_IN_TSAN_READ_16;
+    fcode = is_write ? BUILT_IN_TSAN_WRITE16
+		     : BUILT_IN_TSAN_READ16;
 
   return builtin_decl_implicit (fcode);
 }
@@ -321,6 +323,7 @@  instrument_func_exit (void)
 static unsigned
 tsan_pass (void)
 {
+  initialize_sanitizer_builtins ();
   if (instrument_memory_accesses ())
     {
       instrument_func_entry ();
@@ -334,8 +337,7 @@  tsan_pass (void)
 static bool
 tsan_gate (void)
 {
-  return flag_tsan != 0
-	 && builtin_decl_implicit_p (BUILT_IN_TSAN_INIT);
+  return flag_tsan != 0;
 }
 
 /* Inserts __tsan_init () into the list of CTORs.  */
@@ -343,11 +345,10 @@  tsan_gate (void)
 void
 tsan_finish_file (void)
 {
-  tree ctor_statements;
-  tree init_decl;
+  tree ctor_statements = NULL_TREE;
 
-  ctor_statements = NULL_TREE;
-  init_decl = builtin_decl_implicit (BUILT_IN_TSAN_INIT);
+  initialize_sanitizer_builtins ();
+  tree init_decl = builtin_decl_implicit (BUILT_IN_TSAN_INIT);
   append_to_statement_list (build_call_expr (init_decl, 0),
 			    &ctor_statements);
   cgraph_build_static_cdtor ('I', ctor_statements,
@@ -380,8 +381,7 @@  struct gimple_opt_pass pass_tsan =
 static bool
 tsan_gate_O0 (void)
 {
-  return flag_tsan != 0 && !optimize
-	 && builtin_decl_implicit_p (BUILT_IN_TSAN_INIT);
+  return flag_tsan != 0 && !optimize;
 }
 
 struct gimple_opt_pass pass_tsan_O0 =
--- gcc/builtin-types.def.jj	2012-09-14 14:20:56.000000000 +0200
+++ gcc/builtin-types.def	2012-11-22 14:45:21.918587268 +0100
@@ -253,6 +253,8 @@  DEF_FUNCTION_TYPE_2 (BT_FN_INT_INT_FILEP
 		     BT_INT, BT_INT, BT_FILEPTR)
 DEF_FUNCTION_TYPE_2 (BT_FN_VOID_PTRMODE_PTR,
 		     BT_VOID, BT_PTRMODE, BT_PTR)
+DEF_FUNCTION_TYPE_2 (BT_FN_VOID_PTR_PTRMODE,
+		     BT_VOID, BT_PTR, BT_PTRMODE)
 DEF_FUNCTION_TYPE_2 (BT_FN_VOID_VALIST_REF_VALIST_ARG,
 		     BT_VOID, BT_VALIST_REF, BT_VALIST_ARG)
 DEF_FUNCTION_TYPE_2 (BT_FN_LONG_LONG_LONG,