public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
From: Matthew Malcomson <Matthew.Malcomson@arm.com>
To: "gcc-patches@gcc.gnu.org" <gcc-patches@gcc.gnu.org>
Cc: "mliska@suse.cz" <mliska@suse.cz>,
	"dodji@redhat.com" <dodji@redhat.com>,	nd <nd@arm.com>,
	"kcc@google.com" <kcc@google.com>,
	"jakub@redhat.com"	<jakub@redhat.com>,
	"dvyukov@google.com" <dvyukov@google.com>
Subject: [RFC][PATCH 12/X][libsanitizer] Check pointer tags match address tags
Date: Fri, 06 Sep 2019 14:47:00 -0000	[thread overview]
Message-ID: <VI1PR08MB54715A58DC26A5601AAD7C6AE0BA0@VI1PR08MB5471.eurprd08.prod.outlook.com> (raw)
In-Reply-To: <156778058239.16148.17480879484406897649.scripted-patch-series@arm.com>

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

This adds the `hwasan` pass that puts HWASAN_CHECK internal functions
around memory accesses to check that tags in the pointer being used
match the tag stored in shadow memory for the memory region being used.

These internal functions are expanded into actual checks in the sanopt
pass that happens just before expansion into RTL.

We use the same mechanism that currently inserts ASAN_CHECK internal
functions to insert the new HWASAN_CHECK functions.  Instrumenting
builtin function calls is not yet handled and will be in a later patch
in this series.

As yet we always terminate the program on a tag mismatch, and always
check tags via a library call to libhwasan.  Allowing a program to
continue from tag mismatch, and implementing inline checks are intended
for a later revision.

gcc/ChangeLog:

2019-09-06  Matthew Malcomson  <matthew.malcomson@arm.com>

	* asan.c (build_check_stmt): Generate HWASAN_CHECK for HWASAN.
	(instrument_derefs): Avoid checking global variables for HWASAN.
	(maybe_instrument_call): Temporarily avoid for HWASAN.
	(hwasan_instrument): New.
	(hwasan_expand_check_ifn): New.
	(gate_hwasan): New.
	(class pass_hwasan): New.
	(make_pass_hwasan): New.
	(class pass_hwasan_O0): New.
	(make_pass_hwasan_O0): New.
	* asan.h (hwasan_expand_check_ifn): New.
	(gate_hwasan): New.
	(asan_intercepted_p): No memory function is intercepted by
	libhwasan.
	(asan_sanitize_use_after_scope): True for memory tagging.
	* internal-fn.c (expand_HWASAN_CHECK): New.
	* internal-fn.def (HWASAN_CHECK): New.
	* passes.def (hwasan): New pass.
	* sanitizer.def (BUILT_IN_HWASAN_LOADN): New builtin.
	(BUILT_IN_HWASAN_STOREN): New builtin.
	* sanopt.c (sanopt_optimize_walker): Account for HWASAN_CHECK.
	(pass_sanopt::execute): Account for HWASAN_CHECK.
	* tree-pass.h (make_pass_hwasan, make_pass_hwasan_O0): New decl.



###############     Attachment also inlined for ease of reply    ###############


diff --git a/gcc/asan.h b/gcc/asan.h
index c5492ce35980d0b26d4707f96482b69dc76a525a..68ea1b4afaf9195553251a987df33788421fa142 100644
--- a/gcc/asan.h
+++ b/gcc/asan.h
@@ -32,7 +32,9 @@ extern void hwasan_tag_init ();
 extern rtx hwasan_create_untagged_base (rtx);
 extern void hwasan_emit_prologue (rtx *, rtx *, poly_int64 *, uint8_t *, size_t);
 extern rtx_insn *hwasan_emit_uncolour_frame (rtx, rtx, rtx_insn *);
+extern bool hwasan_expand_check_ifn (gimple_stmt_iterator *, bool);
 extern bool memory_tagging_p (void);
+extern bool gate_hwasan (void);
 extern rtx_insn *asan_emit_stack_protection (rtx, rtx, unsigned int,
 					     HOST_WIDE_INT *, tree *, int);
 extern rtx_insn *asan_emit_allocas_unpoison (rtx, rtx, rtx_insn *);
@@ -188,6 +190,9 @@ extern hash_set<tree> *asan_handled_variables;
 static inline bool
 asan_intercepted_p (enum built_in_function fcode)
 {
+  if (memory_tagging_p ())
+    return false;
+
   return fcode == BUILT_IN_INDEX
 	 || fcode == BUILT_IN_MEMCHR
 	 || fcode == BUILT_IN_MEMCMP
@@ -216,7 +221,8 @@ asan_intercepted_p (enum built_in_function fcode)
 static inline bool
 asan_sanitize_use_after_scope (void)
 {
-  return (flag_sanitize_address_use_after_scope && asan_sanitize_stack_p ());
+  return (flag_sanitize_address_use_after_scope &&
+	  (asan_sanitize_stack_p () || memory_tagging_p ()));
 }
 
 /* Return true if DECL should be guarded on the stack.  */
diff --git a/gcc/asan.c b/gcc/asan.c
index 0e74e32ae6ca4e130b3f13abe110364b119def46..ae1f8a0d28e911c2ff30be8ea9f4001923983cb1 100644
--- a/gcc/asan.c
+++ b/gcc/asan.c
@@ -2177,7 +2177,13 @@ build_check_stmt (location_t loc, tree base, tree len,
   if (is_scalar_access)
     flags |= ASAN_CHECK_SCALAR_ACCESS;
 
-  g = gimple_build_call_internal (IFN_ASAN_CHECK, 4,
+  enum internal_fn fn;
+  if (memory_tagging_p ())
+    fn = IFN_HWASAN_CHECK;
+  else
+    fn = IFN_ASAN_CHECK;
+
+  g = gimple_build_call_internal (fn, 4,
 				  build_int_cst (integer_type_node, flags),
 				  base, len,
 				  build_int_cst (integer_type_node,
@@ -2201,10 +2207,13 @@ static void
 instrument_derefs (gimple_stmt_iterator *iter, tree t,
 		   location_t location, bool is_store)
 {
-  if (is_store && !ASAN_INSTRUMENT_WRITES)
-    return;
-  if (!is_store && !ASAN_INSTRUMENT_READS)
-    return;
+  if (! memory_tagging_p ())
+    {
+    if (is_store && !ASAN_INSTRUMENT_WRITES)
+      return;
+    if (!is_store && !ASAN_INSTRUMENT_READS)
+      return;
+    }
 
   tree type, base;
   HOST_WIDE_INT size_in_bytes;
@@ -2248,10 +2257,21 @@ instrument_derefs (gimple_stmt_iterator *iter, tree t,
       return;
     }
 
+  /* TODO Understand when this can happen.
+      What's the point of ignoring these parts?
+      I guess non-byte sizes would be awkward to instrument?
+      When would this occur?  */
   if (!multiple_p (bitpos, BITS_PER_UNIT)
       || maybe_ne (bitsize, size_in_bytes * BITS_PER_UNIT))
     return;
 
+  /* TODO What are we checking, and why are we not instrumenting that?
+      If the "object" is stored in a register then do nothing?
+      If the "object" is a register then do nothing?
+
+      The second one makes a lot of sense, but I can"t just assume that"s
+      what"s being checked.
+    */
   if (VAR_P (inner) && DECL_HARD_REGISTER (inner))
     return;
 
@@ -2264,7 +2284,8 @@ instrument_derefs (gimple_stmt_iterator *iter, tree t,
     {
       if (DECL_THREAD_LOCAL_P (inner))
 	return;
-      if (!ASAN_GLOBALS && is_global_var (inner))
+      if ((memory_tagging_p () || !ASAN_GLOBALS)
+	  && is_global_var (inner))
         return;
       if (!TREE_STATIC (inner))
 	{
@@ -2472,6 +2493,8 @@ maybe_instrument_assignment (gimple_stmt_iterator *iter)
 static bool
 maybe_instrument_call (gimple_stmt_iterator *iter)
 {
+  if (memory_tagging_p ())
+    return false;
   gimple *stmt = gsi_stmt (*iter);
   bool is_builtin = gimple_call_builtin_p (stmt, BUILT_IN_NORMAL);
 
@@ -3702,6 +3725,17 @@ make_pass_asan_O0 (gcc::context *ctxt)
   return new pass_asan_O0 (ctxt);
 }
 
+/*  HWASAN  */
+static unsigned int
+hwasan_instrument (void)
+{
+  if (shadow_ptr_types[0] == NULL_TREE)
+    asan_init_shadow_ptr_types ();
+  transform_statements ();
+  last_alloca_addr = NULL_TREE;
+  return 0;
+}
+
 void
 hwasan_record_base (rtx base)
 {
@@ -3909,4 +3943,176 @@ hwasan_finish_file (void)
   flag_sanitize |= SANITIZE_HWADDRESS;
 }
 
+bool
+hwasan_expand_check_ifn (gimple_stmt_iterator *iter, bool)
+{
+  // TODO For now only implementing the function when using calls.
+  // This is a little easier, and means I can rely on the library
+  // implementation while checking my instrumentation code for now.
+
+  gimple *g = gsi_stmt (*iter);
+  location_t loc = gimple_location (g);
+  bool recover_p = false;
+  (void)recover_p; // UNUSED for now (will be used to determine action)
+
+  HOST_WIDE_INT flags = tree_to_shwi (gimple_call_arg (g, 0));
+  gcc_assert (flags < ASAN_CHECK_LAST);
+  bool is_scalar_access = (flags & ASAN_CHECK_SCALAR_ACCESS) != 0;
+  bool is_store = (flags & ASAN_CHECK_STORE) != 0;
+  bool is_non_zero_len = (flags & ASAN_CHECK_NON_ZERO_LEN) != 0;
+
+  tree base = gimple_call_arg (g, 1);
+  tree len = gimple_call_arg (g, 2);
+
+  /* TODO align is unused for HWASAN_CHECK, but I pass the argument anyway
+   * because that way I need to write less code.  */
+  /* HOST_WIDE_INT align = tree_to_shwi (gimple_call_arg (g, 3));  */
+
+  unsigned HOST_WIDE_INT size_in_bytes
+    = is_scalar_access && tree_fits_shwi_p (len) ? tree_to_shwi (len) : -1;
+  (void)size_in_bytes; // UNUSED for now (will be used to determine action)
+
+  gimple_stmt_iterator gsi = *iter;
+
+  if (!is_non_zero_len)
+    {
+      /* So, the length of the memory area to hwasan-protect is
+	 non-constant.  Let's guard the generated instrumentation code
+	 like:
+
+	 if (len != 0)
+	   {
+	     // hwasan instrumentation code goes here.
+	   }
+	 // falltrough instructions, starting with *ITER.  */
+
+      g = gimple_build_cond (NE_EXPR,
+			    len,
+			    build_int_cst (TREE_TYPE (len), 0),
+			    NULL_TREE, NULL_TREE);
+      gimple_set_location (g, loc);
+
+      basic_block then_bb, fallthrough_bb;
+      insert_if_then_before_iter (as_a <gcond *> (g), iter,
+				  /*then_more_likely_p=*/true,
+				  &then_bb, &fallthrough_bb);
+      /* Note that fallthrough_bb starts with the statement that was
+	pointed to by ITER.  */
+
+      /* The 'then block' of the 'if (len != 0) condition is where
+	we'll generate the hwasan instrumentation code now.  */
+      gsi = gsi_last_bb (then_bb);
+    }
+
+  /* Instrument using callbacks.  */
+  g = gimple_build_assign (make_ssa_name (pointer_sized_int_node),
+			   NOP_EXPR, base);
+  gimple_set_location (g, loc);
+  gsi_insert_after (&gsi, g, GSI_NEW_STMT);
+  tree base_addr = gimple_assign_lhs (g);
+
+  /* TODO Here we only ever use the LOADN/STOREN functions for checking.
+     This means we always terminate the program on tag mismatch, always use
+     a function call instead of an inline check, and never have the nicer error
+     messages that come from size-specific checking.
+
+     This is much quicker to code for now, all other options will be
+     implemented later.  */
+  enum built_in_function fun_enum =
+    is_store ? BUILT_IN_HWASAN_STOREN : BUILT_IN_HWASAN_LOADN;
+  tree fun = builtin_decl_implicit (fun_enum);
+  g = gimple_build_assign (make_ssa_name (pointer_sized_int_node),
+			   NOP_EXPR, len);
+  gimple_set_location (g, loc);
+  gsi_insert_after (&gsi, g, GSI_NEW_STMT);
+  tree sz_arg = gimple_assign_lhs (g);
+  g = gimple_build_call (fun, 2, base_addr, sz_arg);
+  gimple_set_location (g, loc);
+  gsi_insert_after (&gsi, g, GSI_NEW_STMT);
+
+  gsi_remove (iter, true);
+  *iter = gsi;
+  return false;
+}
+
+bool
+gate_hwasan ()
+{
+  return memory_tagging_p ();
+}
+
+namespace {
+
+const pass_data pass_data_hwasan =
+{
+  GIMPLE_PASS, /* type */
+  "hwasan", /* name */
+  OPTGROUP_NONE, /* optinfo_flags */
+  TV_NONE, /* tv_id */
+  ( PROP_ssa | PROP_cfg | PROP_gimple_leh ), /* properties_required */
+  0, /* properties_provided */
+  0, /* properties_destroyed */
+  0, /* todo_flags_start */
+  TODO_update_ssa, /* todo_flags_finish */
+};
+
+class pass_hwasan : public gimple_opt_pass
+{
+public:
+  pass_hwasan (gcc::context *ctxt)
+    : gimple_opt_pass (pass_data_hwasan, ctxt)
+  {}
+
+  /* opt_pass methods: */
+  opt_pass * clone () { return new pass_hwasan (m_ctxt); }
+  virtual bool gate (function *) { return gate_hwasan (); }
+  virtual unsigned int execute (function *) { return hwasan_instrument (); }
+
+}; // class pass_asan
+
+} // anon namespace
+
+gimple_opt_pass *
+make_pass_hwasan (gcc::context *ctxt)
+{
+  return new pass_hwasan (ctxt);
+}
+
+namespace {
+
+const pass_data pass_data_hwasan_O0 =
+{
+  GIMPLE_PASS, /* type */
+  "hwasan_O0", /* name */
+  OPTGROUP_NONE, /* optinfo_flags */
+  TV_NONE, /* tv_id */
+  ( PROP_ssa | PROP_cfg | PROP_gimple_leh ), /* properties_required */
+  0, /* properties_provided */
+  0, /* properties_destroyed */
+  0, /* todo_flags_start */
+  TODO_update_ssa, /* todo_flags_finish */
+};
+
+class pass_hwasan_O0 : public gimple_opt_pass
+{
+public:
+  pass_hwasan_O0 (gcc::context *ctxt)
+    : gimple_opt_pass (pass_data_hwasan_O0, ctxt)
+  {}
+
+  /* opt_pass methods: */
+  opt_pass * clone () { return new pass_hwasan_O0 (m_ctxt); }
+  virtual bool gate (function *) { return !optimize && gate_hwasan (); }
+  virtual unsigned int execute (function *) { return hwasan_instrument (); }
+
+}; // class pass_asan
+
+} // anon namespace
+
+gimple_opt_pass *
+make_pass_hwasan_O0 (gcc::context *ctxt)
+{
+  return new pass_hwasan_O0 (ctxt);
+}
+
 #include "gt-asan.h"
diff --git a/gcc/internal-fn.c b/gcc/internal-fn.c
index 04081f36c4d31ecfba4099e50412345c67e1f58f..80f94f141bfd92e9f6af13a6df76f0c9ac053fdc 100644
--- a/gcc/internal-fn.c
+++ b/gcc/internal-fn.c
@@ -456,6 +456,12 @@ expand_UBSAN_OBJECT_SIZE (internal_fn, gcall *)
 /* This should get expanded in the sanopt pass.  */
 
 static void
+expand_HWASAN_CHECK (internal_fn, gcall *)
+{
+  gcc_unreachable ();
+}
+
+static void
 expand_ASAN_CHECK (internal_fn, gcall *)
 {
   gcc_unreachable ();
diff --git a/gcc/internal-fn.def b/gcc/internal-fn.def
index 016301a58d83d7128817824d7c7ef92825c7e03e..c683e5d8e5c607f18909bda4d97b58421cb7c2a4 100644
--- a/gcc/internal-fn.def
+++ b/gcc/internal-fn.def
@@ -288,6 +288,7 @@ DEF_INTERNAL_FN (UBSAN_PTR, ECF_LEAF | ECF_NOTHROW, ".R.")
 DEF_INTERNAL_FN (UBSAN_OBJECT_SIZE, ECF_LEAF | ECF_NOTHROW, NULL)
 DEF_INTERNAL_FN (ABNORMAL_DISPATCHER, ECF_NORETURN, NULL)
 DEF_INTERNAL_FN (BUILTIN_EXPECT, ECF_CONST | ECF_LEAF | ECF_NOTHROW, NULL)
+DEF_INTERNAL_FN (HWASAN_CHECK, ECF_TM_PURE | ECF_LEAF | ECF_NOTHROW, "..R..")
 DEF_INTERNAL_FN (ASAN_CHECK, ECF_TM_PURE | ECF_LEAF | ECF_NOTHROW, "..R..")
 DEF_INTERNAL_FN (ASAN_MARK, ECF_LEAF | ECF_NOTHROW, NULL)
 DEF_INTERNAL_FN (ASAN_POISON, ECF_LEAF | ECF_NOTHROW | ECF_NOVOPS, NULL)
diff --git a/gcc/passes.def b/gcc/passes.def
index ad2efabd3853d8d20562f66f4c5bb34694ec80f2..11c9fb20b042d55a7d52da4feda633dc5cd3052a 100644
--- a/gcc/passes.def
+++ b/gcc/passes.def
@@ -246,6 +246,7 @@ along with GCC; see the file COPYING3.  If not see
       NEXT_PASS (pass_sink_code);
       NEXT_PASS (pass_sancov);
       NEXT_PASS (pass_asan);
+      NEXT_PASS (pass_hwasan);
       NEXT_PASS (pass_tsan);
       NEXT_PASS (pass_dce);
       /* Pass group that runs when 1) enabled, 2) there are loops
@@ -362,6 +363,7 @@ along with GCC; see the file COPYING3.  If not see
       NEXT_PASS (pass_dce);
       NEXT_PASS (pass_sancov);
       NEXT_PASS (pass_asan);
+      NEXT_PASS (pass_hwasan);
       NEXT_PASS (pass_tsan);
       /* ???  We do want some kind of loop invariant motion, but we possibly
          need to adjust LIM to be more friendly towards preserving accurate
@@ -387,6 +389,7 @@ along with GCC; see the file COPYING3.  If not see
   NEXT_PASS (pass_sancov_O0);
   NEXT_PASS (pass_lower_switch_O0);
   NEXT_PASS (pass_asan_O0);
+  NEXT_PASS (pass_hwasan_O0);
   NEXT_PASS (pass_tsan_O0);
   NEXT_PASS (pass_sanopt);
   NEXT_PASS (pass_cleanup_eh);
diff --git a/gcc/sanitizer.def b/gcc/sanitizer.def
index 7bd50715f24a2cb154b578e2abdea4e8fcdb2107..0edf349cc23e846608b89d54a1024b9d99de9c4d 100644
--- a/gcc/sanitizer.def
+++ b/gcc/sanitizer.def
@@ -183,6 +183,10 @@ DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_POINTER_SUBTRACT, "__sanitizer_ptr_sub",
 /* Hardware Address Sanitizer.  */
 DEF_SANITIZER_BUILTIN(BUILT_IN_HWASAN_INIT, "__hwasan_init",
 		      BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN(BUILT_IN_HWASAN_LOADN, "__hwasan_loadN",
+		      BT_FN_VOID_PTR_PTRMODE, ATTR_TMPURE_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN(BUILT_IN_HWASAN_STOREN, "__hwasan_storeN",
+		      BT_FN_VOID_PTR_PTRMODE, ATTR_TMPURE_NOTHROW_LEAF_LIST)
 DEF_SANITIZER_BUILTIN(BUILT_IN_HWASAN_TAG_MEM, "__hwasan_tag_memory",
 		      BT_FN_VOID_PTR_UINT8_SIZE, ATTR_NOTHROW_LIST)
 
diff --git a/gcc/sanopt.c b/gcc/sanopt.c
index 5cb98e1b50e4e1644072bd18d74797c3cac43c3f..31270153f3cf56bfbad593830de1b9334e7f65d1 100644
--- a/gcc/sanopt.c
+++ b/gcc/sanopt.c
@@ -772,7 +772,8 @@ sanopt_optimize_walker (basic_block bb, struct sanopt_ctx *ctx)
   basic_block son;
   gimple_stmt_iterator gsi;
   sanopt_info *info = (sanopt_info *) bb->aux;
-  bool asan_check_optimize = (flag_sanitize & SANITIZE_ADDRESS) != 0;
+  bool asan_check_optimize =
+    ((flag_sanitize & SANITIZE_ADDRESS) != 0) || memory_tagging_p ();
 
   for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi);)
     {
@@ -802,6 +803,7 @@ sanopt_optimize_walker (basic_block bb, struct sanopt_ctx *ctx)
       if (asan_check_optimize
 	  && gimple_call_builtin_p (stmt, BUILT_IN_ASAN_BEFORE_DYNAMIC_INIT))
 	{
+	  gcc_assert (!memory_tagging_p ());
 	  use_operand_p use;
 	  gimple *use_stmt;
 	  if (single_imm_use (gimple_vdef (stmt), &use, &use_stmt))
@@ -830,6 +832,7 @@ sanopt_optimize_walker (basic_block bb, struct sanopt_ctx *ctx)
 	  case IFN_UBSAN_PTR:
 	    remove = maybe_optimize_ubsan_ptr_ifn (ctx, stmt);
 	    break;
+	  case IFN_HWASAN_CHECK:
 	  case IFN_ASAN_CHECK:
 	    if (asan_check_optimize)
 	      remove = maybe_optimize_asan_check_ifn (ctx, stmt);
@@ -1262,10 +1265,11 @@ pass_sanopt::execute (function *fun)
   /* Try to remove redundant checks.  */
   if (optimize
       && (flag_sanitize
-	  & (SANITIZE_NULL | SANITIZE_ALIGNMENT
+	  & (SANITIZE_NULL | SANITIZE_ALIGNMENT | SANITIZE_HWADDRESS
 	     | SANITIZE_ADDRESS | SANITIZE_VPTR | SANITIZE_POINTER_OVERFLOW)))
     asan_num_accesses = sanopt_optimize (fun, &contains_asan_mark);
-  else if (flag_sanitize & SANITIZE_ADDRESS)
+  else if (flag_sanitize & SANITIZE_ADDRESS
+	   || memory_tagging_p ())
     {
       gimple_stmt_iterator gsi;
       FOR_EACH_BB_FN (bb, fun)
@@ -1285,7 +1289,7 @@ pass_sanopt::execute (function *fun)
       sanitize_asan_mark_poison ();
     }
 
-  if (asan_sanitize_stack_p ())
+  if (asan_sanitize_stack_p () || memory_tagging_p ())
     sanitize_rewrite_addressable_params (fun);
 
   bool use_calls = ASAN_INSTRUMENTATION_WITH_CALL_THRESHOLD < INT_MAX
@@ -1327,6 +1331,9 @@ pass_sanopt::execute (function *fun)
 		case IFN_UBSAN_VPTR:
 		  no_next = ubsan_expand_vptr_ifn (&gsi);
 		  break;
+		case IFN_HWASAN_CHECK:
+		  no_next = hwasan_expand_check_ifn (&gsi, use_calls);
+		  break;
 		case IFN_ASAN_CHECK:
 		  no_next = asan_expand_check_ifn (&gsi, use_calls);
 		  break;
diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h
index 3a0b3805d24dbd50141d4145563861e4ae3768f3..01ebd03205e57ee3a63d3344da8098160c081002 100644
--- a/gcc/tree-pass.h
+++ b/gcc/tree-pass.h
@@ -341,6 +341,8 @@ extern void register_pass (opt_pass* pass, pass_positioning_ops pos,
 
 extern gimple_opt_pass *make_pass_asan (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_asan_O0 (gcc::context *ctxt);
+extern gimple_opt_pass *make_pass_hwasan (gcc::context *ctxt);
+extern gimple_opt_pass *make_pass_hwasan_O0 (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_tsan (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_tsan_O0 (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_sancov (gcc::context *ctxt);


[-- Attachment #2: hwasan-implementation11.patch --]
[-- Type: text/plain, Size: 16144 bytes --]

diff --git a/gcc/asan.h b/gcc/asan.h
index c5492ce35980d0b26d4707f96482b69dc76a525a..68ea1b4afaf9195553251a987df33788421fa142 100644
--- a/gcc/asan.h
+++ b/gcc/asan.h
@@ -32,7 +32,9 @@ extern void hwasan_tag_init ();
 extern rtx hwasan_create_untagged_base (rtx);
 extern void hwasan_emit_prologue (rtx *, rtx *, poly_int64 *, uint8_t *, size_t);
 extern rtx_insn *hwasan_emit_uncolour_frame (rtx, rtx, rtx_insn *);
+extern bool hwasan_expand_check_ifn (gimple_stmt_iterator *, bool);
 extern bool memory_tagging_p (void);
+extern bool gate_hwasan (void);
 extern rtx_insn *asan_emit_stack_protection (rtx, rtx, unsigned int,
 					     HOST_WIDE_INT *, tree *, int);
 extern rtx_insn *asan_emit_allocas_unpoison (rtx, rtx, rtx_insn *);
@@ -188,6 +190,9 @@ extern hash_set<tree> *asan_handled_variables;
 static inline bool
 asan_intercepted_p (enum built_in_function fcode)
 {
+  if (memory_tagging_p ())
+    return false;
+
   return fcode == BUILT_IN_INDEX
 	 || fcode == BUILT_IN_MEMCHR
 	 || fcode == BUILT_IN_MEMCMP
@@ -216,7 +221,8 @@ asan_intercepted_p (enum built_in_function fcode)
 static inline bool
 asan_sanitize_use_after_scope (void)
 {
-  return (flag_sanitize_address_use_after_scope && asan_sanitize_stack_p ());
+  return (flag_sanitize_address_use_after_scope &&
+	  (asan_sanitize_stack_p () || memory_tagging_p ()));
 }
 
 /* Return true if DECL should be guarded on the stack.  */
diff --git a/gcc/asan.c b/gcc/asan.c
index 0e74e32ae6ca4e130b3f13abe110364b119def46..ae1f8a0d28e911c2ff30be8ea9f4001923983cb1 100644
--- a/gcc/asan.c
+++ b/gcc/asan.c
@@ -2177,7 +2177,13 @@ build_check_stmt (location_t loc, tree base, tree len,
   if (is_scalar_access)
     flags |= ASAN_CHECK_SCALAR_ACCESS;
 
-  g = gimple_build_call_internal (IFN_ASAN_CHECK, 4,
+  enum internal_fn fn;
+  if (memory_tagging_p ())
+    fn = IFN_HWASAN_CHECK;
+  else
+    fn = IFN_ASAN_CHECK;
+
+  g = gimple_build_call_internal (fn, 4,
 				  build_int_cst (integer_type_node, flags),
 				  base, len,
 				  build_int_cst (integer_type_node,
@@ -2201,10 +2207,13 @@ static void
 instrument_derefs (gimple_stmt_iterator *iter, tree t,
 		   location_t location, bool is_store)
 {
-  if (is_store && !ASAN_INSTRUMENT_WRITES)
-    return;
-  if (!is_store && !ASAN_INSTRUMENT_READS)
-    return;
+  if (! memory_tagging_p ())
+    {
+    if (is_store && !ASAN_INSTRUMENT_WRITES)
+      return;
+    if (!is_store && !ASAN_INSTRUMENT_READS)
+      return;
+    }
 
   tree type, base;
   HOST_WIDE_INT size_in_bytes;
@@ -2248,10 +2257,21 @@ instrument_derefs (gimple_stmt_iterator *iter, tree t,
       return;
     }
 
+  /* TODO Understand when this can happen.
+      What's the point of ignoring these parts?
+      I guess non-byte sizes would be awkward to instrument?
+      When would this occur?  */
   if (!multiple_p (bitpos, BITS_PER_UNIT)
       || maybe_ne (bitsize, size_in_bytes * BITS_PER_UNIT))
     return;
 
+  /* TODO What are we checking, and why are we not instrumenting that?
+      If the "object" is stored in a register then do nothing?
+      If the "object" is a register then do nothing?
+
+      The second one makes a lot of sense, but I can"t just assume that"s
+      what"s being checked.
+    */
   if (VAR_P (inner) && DECL_HARD_REGISTER (inner))
     return;
 
@@ -2264,7 +2284,8 @@ instrument_derefs (gimple_stmt_iterator *iter, tree t,
     {
       if (DECL_THREAD_LOCAL_P (inner))
 	return;
-      if (!ASAN_GLOBALS && is_global_var (inner))
+      if ((memory_tagging_p () || !ASAN_GLOBALS)
+	  && is_global_var (inner))
         return;
       if (!TREE_STATIC (inner))
 	{
@@ -2472,6 +2493,8 @@ maybe_instrument_assignment (gimple_stmt_iterator *iter)
 static bool
 maybe_instrument_call (gimple_stmt_iterator *iter)
 {
+  if (memory_tagging_p ())
+    return false;
   gimple *stmt = gsi_stmt (*iter);
   bool is_builtin = gimple_call_builtin_p (stmt, BUILT_IN_NORMAL);
 
@@ -3702,6 +3725,17 @@ make_pass_asan_O0 (gcc::context *ctxt)
   return new pass_asan_O0 (ctxt);
 }
 
+/*  HWASAN  */
+static unsigned int
+hwasan_instrument (void)
+{
+  if (shadow_ptr_types[0] == NULL_TREE)
+    asan_init_shadow_ptr_types ();
+  transform_statements ();
+  last_alloca_addr = NULL_TREE;
+  return 0;
+}
+
 void
 hwasan_record_base (rtx base)
 {
@@ -3909,4 +3943,176 @@ hwasan_finish_file (void)
   flag_sanitize |= SANITIZE_HWADDRESS;
 }
 
+bool
+hwasan_expand_check_ifn (gimple_stmt_iterator *iter, bool)
+{
+  // TODO For now only implementing the function when using calls.
+  // This is a little easier, and means I can rely on the library
+  // implementation while checking my instrumentation code for now.
+
+  gimple *g = gsi_stmt (*iter);
+  location_t loc = gimple_location (g);
+  bool recover_p = false;
+  (void)recover_p; // UNUSED for now (will be used to determine action)
+
+  HOST_WIDE_INT flags = tree_to_shwi (gimple_call_arg (g, 0));
+  gcc_assert (flags < ASAN_CHECK_LAST);
+  bool is_scalar_access = (flags & ASAN_CHECK_SCALAR_ACCESS) != 0;
+  bool is_store = (flags & ASAN_CHECK_STORE) != 0;
+  bool is_non_zero_len = (flags & ASAN_CHECK_NON_ZERO_LEN) != 0;
+
+  tree base = gimple_call_arg (g, 1);
+  tree len = gimple_call_arg (g, 2);
+
+  /* TODO align is unused for HWASAN_CHECK, but I pass the argument anyway
+   * because that way I need to write less code.  */
+  /* HOST_WIDE_INT align = tree_to_shwi (gimple_call_arg (g, 3));  */
+
+  unsigned HOST_WIDE_INT size_in_bytes
+    = is_scalar_access && tree_fits_shwi_p (len) ? tree_to_shwi (len) : -1;
+  (void)size_in_bytes; // UNUSED for now (will be used to determine action)
+
+  gimple_stmt_iterator gsi = *iter;
+
+  if (!is_non_zero_len)
+    {
+      /* So, the length of the memory area to hwasan-protect is
+	 non-constant.  Let's guard the generated instrumentation code
+	 like:
+
+	 if (len != 0)
+	   {
+	     // hwasan instrumentation code goes here.
+	   }
+	 // falltrough instructions, starting with *ITER.  */
+
+      g = gimple_build_cond (NE_EXPR,
+			    len,
+			    build_int_cst (TREE_TYPE (len), 0),
+			    NULL_TREE, NULL_TREE);
+      gimple_set_location (g, loc);
+
+      basic_block then_bb, fallthrough_bb;
+      insert_if_then_before_iter (as_a <gcond *> (g), iter,
+				  /*then_more_likely_p=*/true,
+				  &then_bb, &fallthrough_bb);
+      /* Note that fallthrough_bb starts with the statement that was
+	pointed to by ITER.  */
+
+      /* The 'then block' of the 'if (len != 0) condition is where
+	we'll generate the hwasan instrumentation code now.  */
+      gsi = gsi_last_bb (then_bb);
+    }
+
+  /* Instrument using callbacks.  */
+  g = gimple_build_assign (make_ssa_name (pointer_sized_int_node),
+			   NOP_EXPR, base);
+  gimple_set_location (g, loc);
+  gsi_insert_after (&gsi, g, GSI_NEW_STMT);
+  tree base_addr = gimple_assign_lhs (g);
+
+  /* TODO Here we only ever use the LOADN/STOREN functions for checking.
+     This means we always terminate the program on tag mismatch, always use
+     a function call instead of an inline check, and never have the nicer error
+     messages that come from size-specific checking.
+
+     This is much quicker to code for now, all other options will be
+     implemented later.  */
+  enum built_in_function fun_enum =
+    is_store ? BUILT_IN_HWASAN_STOREN : BUILT_IN_HWASAN_LOADN;
+  tree fun = builtin_decl_implicit (fun_enum);
+  g = gimple_build_assign (make_ssa_name (pointer_sized_int_node),
+			   NOP_EXPR, len);
+  gimple_set_location (g, loc);
+  gsi_insert_after (&gsi, g, GSI_NEW_STMT);
+  tree sz_arg = gimple_assign_lhs (g);
+  g = gimple_build_call (fun, 2, base_addr, sz_arg);
+  gimple_set_location (g, loc);
+  gsi_insert_after (&gsi, g, GSI_NEW_STMT);
+
+  gsi_remove (iter, true);
+  *iter = gsi;
+  return false;
+}
+
+bool
+gate_hwasan ()
+{
+  return memory_tagging_p ();
+}
+
+namespace {
+
+const pass_data pass_data_hwasan =
+{
+  GIMPLE_PASS, /* type */
+  "hwasan", /* name */
+  OPTGROUP_NONE, /* optinfo_flags */
+  TV_NONE, /* tv_id */
+  ( PROP_ssa | PROP_cfg | PROP_gimple_leh ), /* properties_required */
+  0, /* properties_provided */
+  0, /* properties_destroyed */
+  0, /* todo_flags_start */
+  TODO_update_ssa, /* todo_flags_finish */
+};
+
+class pass_hwasan : public gimple_opt_pass
+{
+public:
+  pass_hwasan (gcc::context *ctxt)
+    : gimple_opt_pass (pass_data_hwasan, ctxt)
+  {}
+
+  /* opt_pass methods: */
+  opt_pass * clone () { return new pass_hwasan (m_ctxt); }
+  virtual bool gate (function *) { return gate_hwasan (); }
+  virtual unsigned int execute (function *) { return hwasan_instrument (); }
+
+}; // class pass_asan
+
+} // anon namespace
+
+gimple_opt_pass *
+make_pass_hwasan (gcc::context *ctxt)
+{
+  return new pass_hwasan (ctxt);
+}
+
+namespace {
+
+const pass_data pass_data_hwasan_O0 =
+{
+  GIMPLE_PASS, /* type */
+  "hwasan_O0", /* name */
+  OPTGROUP_NONE, /* optinfo_flags */
+  TV_NONE, /* tv_id */
+  ( PROP_ssa | PROP_cfg | PROP_gimple_leh ), /* properties_required */
+  0, /* properties_provided */
+  0, /* properties_destroyed */
+  0, /* todo_flags_start */
+  TODO_update_ssa, /* todo_flags_finish */
+};
+
+class pass_hwasan_O0 : public gimple_opt_pass
+{
+public:
+  pass_hwasan_O0 (gcc::context *ctxt)
+    : gimple_opt_pass (pass_data_hwasan_O0, ctxt)
+  {}
+
+  /* opt_pass methods: */
+  opt_pass * clone () { return new pass_hwasan_O0 (m_ctxt); }
+  virtual bool gate (function *) { return !optimize && gate_hwasan (); }
+  virtual unsigned int execute (function *) { return hwasan_instrument (); }
+
+}; // class pass_asan
+
+} // anon namespace
+
+gimple_opt_pass *
+make_pass_hwasan_O0 (gcc::context *ctxt)
+{
+  return new pass_hwasan_O0 (ctxt);
+}
+
 #include "gt-asan.h"
diff --git a/gcc/internal-fn.c b/gcc/internal-fn.c
index 04081f36c4d31ecfba4099e50412345c67e1f58f..80f94f141bfd92e9f6af13a6df76f0c9ac053fdc 100644
--- a/gcc/internal-fn.c
+++ b/gcc/internal-fn.c
@@ -456,6 +456,12 @@ expand_UBSAN_OBJECT_SIZE (internal_fn, gcall *)
 /* This should get expanded in the sanopt pass.  */
 
 static void
+expand_HWASAN_CHECK (internal_fn, gcall *)
+{
+  gcc_unreachable ();
+}
+
+static void
 expand_ASAN_CHECK (internal_fn, gcall *)
 {
   gcc_unreachable ();
diff --git a/gcc/internal-fn.def b/gcc/internal-fn.def
index 016301a58d83d7128817824d7c7ef92825c7e03e..c683e5d8e5c607f18909bda4d97b58421cb7c2a4 100644
--- a/gcc/internal-fn.def
+++ b/gcc/internal-fn.def
@@ -288,6 +288,7 @@ DEF_INTERNAL_FN (UBSAN_PTR, ECF_LEAF | ECF_NOTHROW, ".R.")
 DEF_INTERNAL_FN (UBSAN_OBJECT_SIZE, ECF_LEAF | ECF_NOTHROW, NULL)
 DEF_INTERNAL_FN (ABNORMAL_DISPATCHER, ECF_NORETURN, NULL)
 DEF_INTERNAL_FN (BUILTIN_EXPECT, ECF_CONST | ECF_LEAF | ECF_NOTHROW, NULL)
+DEF_INTERNAL_FN (HWASAN_CHECK, ECF_TM_PURE | ECF_LEAF | ECF_NOTHROW, "..R..")
 DEF_INTERNAL_FN (ASAN_CHECK, ECF_TM_PURE | ECF_LEAF | ECF_NOTHROW, "..R..")
 DEF_INTERNAL_FN (ASAN_MARK, ECF_LEAF | ECF_NOTHROW, NULL)
 DEF_INTERNAL_FN (ASAN_POISON, ECF_LEAF | ECF_NOTHROW | ECF_NOVOPS, NULL)
diff --git a/gcc/passes.def b/gcc/passes.def
index ad2efabd3853d8d20562f66f4c5bb34694ec80f2..11c9fb20b042d55a7d52da4feda633dc5cd3052a 100644
--- a/gcc/passes.def
+++ b/gcc/passes.def
@@ -246,6 +246,7 @@ along with GCC; see the file COPYING3.  If not see
       NEXT_PASS (pass_sink_code);
       NEXT_PASS (pass_sancov);
       NEXT_PASS (pass_asan);
+      NEXT_PASS (pass_hwasan);
       NEXT_PASS (pass_tsan);
       NEXT_PASS (pass_dce);
       /* Pass group that runs when 1) enabled, 2) there are loops
@@ -362,6 +363,7 @@ along with GCC; see the file COPYING3.  If not see
       NEXT_PASS (pass_dce);
       NEXT_PASS (pass_sancov);
       NEXT_PASS (pass_asan);
+      NEXT_PASS (pass_hwasan);
       NEXT_PASS (pass_tsan);
       /* ???  We do want some kind of loop invariant motion, but we possibly
          need to adjust LIM to be more friendly towards preserving accurate
@@ -387,6 +389,7 @@ along with GCC; see the file COPYING3.  If not see
   NEXT_PASS (pass_sancov_O0);
   NEXT_PASS (pass_lower_switch_O0);
   NEXT_PASS (pass_asan_O0);
+  NEXT_PASS (pass_hwasan_O0);
   NEXT_PASS (pass_tsan_O0);
   NEXT_PASS (pass_sanopt);
   NEXT_PASS (pass_cleanup_eh);
diff --git a/gcc/sanitizer.def b/gcc/sanitizer.def
index 7bd50715f24a2cb154b578e2abdea4e8fcdb2107..0edf349cc23e846608b89d54a1024b9d99de9c4d 100644
--- a/gcc/sanitizer.def
+++ b/gcc/sanitizer.def
@@ -183,6 +183,10 @@ DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_POINTER_SUBTRACT, "__sanitizer_ptr_sub",
 /* Hardware Address Sanitizer.  */
 DEF_SANITIZER_BUILTIN(BUILT_IN_HWASAN_INIT, "__hwasan_init",
 		      BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN(BUILT_IN_HWASAN_LOADN, "__hwasan_loadN",
+		      BT_FN_VOID_PTR_PTRMODE, ATTR_TMPURE_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN(BUILT_IN_HWASAN_STOREN, "__hwasan_storeN",
+		      BT_FN_VOID_PTR_PTRMODE, ATTR_TMPURE_NOTHROW_LEAF_LIST)
 DEF_SANITIZER_BUILTIN(BUILT_IN_HWASAN_TAG_MEM, "__hwasan_tag_memory",
 		      BT_FN_VOID_PTR_UINT8_SIZE, ATTR_NOTHROW_LIST)
 
diff --git a/gcc/sanopt.c b/gcc/sanopt.c
index 5cb98e1b50e4e1644072bd18d74797c3cac43c3f..31270153f3cf56bfbad593830de1b9334e7f65d1 100644
--- a/gcc/sanopt.c
+++ b/gcc/sanopt.c
@@ -772,7 +772,8 @@ sanopt_optimize_walker (basic_block bb, struct sanopt_ctx *ctx)
   basic_block son;
   gimple_stmt_iterator gsi;
   sanopt_info *info = (sanopt_info *) bb->aux;
-  bool asan_check_optimize = (flag_sanitize & SANITIZE_ADDRESS) != 0;
+  bool asan_check_optimize =
+    ((flag_sanitize & SANITIZE_ADDRESS) != 0) || memory_tagging_p ();
 
   for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi);)
     {
@@ -802,6 +803,7 @@ sanopt_optimize_walker (basic_block bb, struct sanopt_ctx *ctx)
       if (asan_check_optimize
 	  && gimple_call_builtin_p (stmt, BUILT_IN_ASAN_BEFORE_DYNAMIC_INIT))
 	{
+	  gcc_assert (!memory_tagging_p ());
 	  use_operand_p use;
 	  gimple *use_stmt;
 	  if (single_imm_use (gimple_vdef (stmt), &use, &use_stmt))
@@ -830,6 +832,7 @@ sanopt_optimize_walker (basic_block bb, struct sanopt_ctx *ctx)
 	  case IFN_UBSAN_PTR:
 	    remove = maybe_optimize_ubsan_ptr_ifn (ctx, stmt);
 	    break;
+	  case IFN_HWASAN_CHECK:
 	  case IFN_ASAN_CHECK:
 	    if (asan_check_optimize)
 	      remove = maybe_optimize_asan_check_ifn (ctx, stmt);
@@ -1262,10 +1265,11 @@ pass_sanopt::execute (function *fun)
   /* Try to remove redundant checks.  */
   if (optimize
       && (flag_sanitize
-	  & (SANITIZE_NULL | SANITIZE_ALIGNMENT
+	  & (SANITIZE_NULL | SANITIZE_ALIGNMENT | SANITIZE_HWADDRESS
 	     | SANITIZE_ADDRESS | SANITIZE_VPTR | SANITIZE_POINTER_OVERFLOW)))
     asan_num_accesses = sanopt_optimize (fun, &contains_asan_mark);
-  else if (flag_sanitize & SANITIZE_ADDRESS)
+  else if (flag_sanitize & SANITIZE_ADDRESS
+	   || memory_tagging_p ())
     {
       gimple_stmt_iterator gsi;
       FOR_EACH_BB_FN (bb, fun)
@@ -1285,7 +1289,7 @@ pass_sanopt::execute (function *fun)
       sanitize_asan_mark_poison ();
     }
 
-  if (asan_sanitize_stack_p ())
+  if (asan_sanitize_stack_p () || memory_tagging_p ())
     sanitize_rewrite_addressable_params (fun);
 
   bool use_calls = ASAN_INSTRUMENTATION_WITH_CALL_THRESHOLD < INT_MAX
@@ -1327,6 +1331,9 @@ pass_sanopt::execute (function *fun)
 		case IFN_UBSAN_VPTR:
 		  no_next = ubsan_expand_vptr_ifn (&gsi);
 		  break;
+		case IFN_HWASAN_CHECK:
+		  no_next = hwasan_expand_check_ifn (&gsi, use_calls);
+		  break;
 		case IFN_ASAN_CHECK:
 		  no_next = asan_expand_check_ifn (&gsi, use_calls);
 		  break;
diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h
index 3a0b3805d24dbd50141d4145563861e4ae3768f3..01ebd03205e57ee3a63d3344da8098160c081002 100644
--- a/gcc/tree-pass.h
+++ b/gcc/tree-pass.h
@@ -341,6 +341,8 @@ extern void register_pass (opt_pass* pass, pass_positioning_ops pos,
 
 extern gimple_opt_pass *make_pass_asan (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_asan_O0 (gcc::context *ctxt);
+extern gimple_opt_pass *make_pass_hwasan (gcc::context *ctxt);
+extern gimple_opt_pass *make_pass_hwasan_O0 (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_tsan (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_tsan_O0 (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_sancov (gcc::context *ctxt);


  parent reply	other threads:[~2019-09-06 14:46 UTC|newest]

Thread overview: 35+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-09-06 14:46 [Patch 0/X] [WIP][RFC][libsanitizer] Introduce HWASAN to GCC Matthew Malcomson
2019-09-06 14:46 ` [RFC][PATCH 7/X][libsanitizer] Add option to bootstrap using HWASAN Matthew Malcomson
2019-09-06 14:46 ` [RFC][PATCH 5/X][libsanitizer] Introduce longjmp/setjmp interceptors to libhwasan Matthew Malcomson
2019-09-09 10:02   ` Martin Liška
2019-09-09 10:29     ` Matthew Malcomson
2019-09-09 10:49       ` Martin Liška
2019-09-06 14:46 ` [RFC][PATCH 8/X][libsanitizer] Ensure HWASAN required alignment for stack variables Matthew Malcomson
2019-09-06 14:46 ` [RFC][PATCH 3/X][libsanitizer] Allow compilation for HWASAN_WITH_INTERCEPTORS=OFF Matthew Malcomson
2019-09-09  9:27   ` Martin Liška
2019-09-06 14:46 ` [RFC][PATCH 4/X][libsanitizer] Pass size and pointer info to error reporting functions Matthew Malcomson
2019-09-09  9:27   ` Martin Liška
2019-09-06 14:46 ` [RFC][PATCH 2/X][libsanitizer] Tie the hwasan library into our build system Matthew Malcomson
2019-09-06 14:46 ` [RFC][PATCH 1/X][libsanitizer] Introduce libsanitizer to GCC tree Matthew Malcomson
2019-09-09  9:26   ` Martin Liška
2019-09-06 14:46 ` [RFC][PATCH 14/X][libsanitizer] Introduce HWASAN block-scope poisoning Matthew Malcomson
2019-09-06 14:47 ` [RFC][PATCH 10/X][libsanitizer] Colour the shadow stack for each stack variable Matthew Malcomson
2019-09-06 14:47 ` [RFC][PATCH 13/X][libsanitizer] Instrument known builtin function calls Matthew Malcomson
2019-09-06 14:47 ` Matthew Malcomson [this message]
2019-09-06 14:47 ` [RFC][PATCH 15/X][libsanitizer] Add in MTE stubs Matthew Malcomson
2019-09-06 14:47 ` [RFC][PATCH 11/X][libsanitizer] Uncolour stack frame on function exit Matthew Malcomson
2019-09-06 14:47 ` [RFC][PATCH 16/X][libsanitizer] Build libhwasan with interceptors Matthew Malcomson
2019-09-06 14:47 ` [RFC][PATCH 9/X][libsanitizer] Put tags into each stack variable pointer Matthew Malcomson
2019-09-06 14:47 ` [RFC][PATCH 6/X][libsanitizer] Add -fsanitize=hwaddress flags Matthew Malcomson
2019-09-09 10:06   ` Martin Liška
2019-09-09 10:18     ` Matthew Malcomson
2019-09-09 10:20       ` Martin Liška
2019-09-09 10:47 ` [Patch 0/X] [WIP][RFC][libsanitizer] Introduce HWASAN to GCC Martin Liška
2019-09-09 15:55   ` Matthew Malcomson
2019-09-10  1:06     ` Kostya Serebryany via gcc-patches
2019-09-11 11:53     ` Martin Liška
2019-09-11 16:37       ` Matthew Malcomson
2019-09-11 18:34         ` Evgenii Stepanov via gcc-patches
2019-09-23  8:02 ` Martin Liška
2019-10-23 11:02   ` Matthew Malcomson
2019-10-24 10:11     ` Martin Liška

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=VI1PR08MB54715A58DC26A5601AAD7C6AE0BA0@VI1PR08MB5471.eurprd08.prod.outlook.com \
    --to=matthew.malcomson@arm.com \
    --cc=dodji@redhat.com \
    --cc=dvyukov@google.com \
    --cc=gcc-patches@gcc.gnu.org \
    --cc=jakub@redhat.com \
    --cc=kcc@google.com \
    --cc=mliska@suse.cz \
    --cc=nd@arm.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).