This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] -fsanitize=alignment support


Hi!

This patch adds -fsanitize=alignment support, part of -fsanitize=undefined,
which will complain about misaligned accesses (those where the compiler
isn't told it is less than naturally aligned access, such as with packed
struct accesses).
In addition to that it adds instrumentation of reference initialization
for C++ (in that case it checks for -fsanitize=null whether a reference
doesn't bind to what a NULL pointer points to and for -fsanitize=alignment
whether it is sufficiently aligned).
And also instruments method calls and constructor calls, the former for
both null and alignment, the latter only for alignment, as for placement
new we don't construct anything at NULL address.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

2014-07-04  Jakub Jelinek  <jakub@redhat.com>

	* opts.c (common_handle_option): Handle -fsanitize=alignment.
	* ubsan.h (enum ubsan_null_ckind): Add UBSAN_CTOR_CALL.
	(ubsan_expand_bounds_ifn, ubsan_expand_null_ifn): Change return
	type to bool.
	* stor-layout.h (min_align_of_type): New prototype.
	* asan.c (pass_sanopt::execute): Don't perform gsi_next if
	ubsan_expand* told us not to do it.  Remove the extra gsi_end_p
	check.
	* ubsan.c: Include builtins.h.
	(ubsan_expand_bounds_ifn): Change return type to bool,
	always return true.
	(ubsan_expand_null_ifn): Change return type to bool, change
	argument to gimple_stmt_iterator *.  Handle both null and alignment
	sanitization, take type from ckind argument's type rather than
	first argument.
	(instrument_member_call): Removed.
	(instrument_mem_ref): Remove t argument, add mem and base arguments.
	Handle both null and alignment sanitization, don't say whole
	struct access is member access.  Build 3 argument IFN_UBSAN_NULL
	call instead of 2 argument.
	(instrument_null): Adjust instrument_mem_ref caller.  Don't
	instrument calls here.
	(pass_ubsan::gate, pass_ubsan::execute): Handle SANITIZE_ALIGNMENT
	like SANITIZE_NULL.
	* stor-layout.c (min_align_of_type): New function.
	* flag-types.h (enum sanitize_code): Add SANITIZE_ALIGNMENT.
	Or it into SANITIZE_UNDEFINED.
	* doc/invoke.texi (-fsanitize=alignment): Document.
cp/
	* cp-gimplify.c (cp_genericize_r): For -fsanitize=null and/or
	-fsanitize=alignment call ubsan_maybe_instrument_reference
	for casts to REFERENCE_TYPE and ubsan_maybe_instrument_member_call
	for calls to member functions.
c-family/
	* c-common.h (min_align_of_type): Removed prototype.
	* c-common.c (min_align_of_type): Removed.
	* c-ubsan.h (ubsan_maybe_instrument_reference,
	ubsan_maybe_instrument_member_call): New prototypes.
	* c-ubsan.c: Include stor-layout.h and builtins.h.
	(ubsan_maybe_instrument_reference_or_call,
	ubsan_maybe_instrument_reference, ubsan_maybe_instrument_call): New
	functions.
testsuite/
	* c-c++-common/ubsan/align-1.c: New test.
	* c-c++-common/ubsan/align-2.c: New test.
	* c-c++-common/ubsan/align-3.c: New test.
	* c-c++-common/ubsan/align-4.c: New test.
	* c-c++-common/ubsan/align-5.c: New test.
	* c-c++-common/ubsan/attrib-4.c: New test.
	* g++.dg/ubsan/align-1.C: New test.
	* g++.dg/ubsan/align-2.C: New test.
	* g++.dg/ubsan/align-3.C: New test.
	* g++.dg/ubsan/attrib-1.C: New test.
	* g++.dg/ubsan/null-1.C: New test.
	* g++.dg/ubsan/null-2.C: New test.

--- gcc/opts.c.jj	2014-07-03 16:35:57.364165700 +0200
+++ gcc/opts.c	2014-07-04 10:58:10.844536974 +0200
@@ -1475,6 +1475,7 @@ common_handle_option (struct gcc_options
 	      { "float-cast-overflow", SANITIZE_FLOAT_CAST,
 		sizeof "float-cast-overflow" - 1 },
 	      { "bounds", SANITIZE_BOUNDS, sizeof "bounds" - 1 },
+	      { "alignment", SANITIZE_ALIGNMENT, sizeof "alignment" - 1 },
 	      { NULL, 0, 0 }
 	    };
 	    const char *comma;
--- gcc/ubsan.h.jj	2014-07-03 16:35:57.012167511 +0200
+++ gcc/ubsan.h	2014-07-04 14:49:24.125733716 +0200
@@ -27,7 +27,8 @@ enum ubsan_null_ckind {
   UBSAN_STORE_OF,
   UBSAN_REF_BINDING,
   UBSAN_MEMBER_ACCESS,
-  UBSAN_MEMBER_CALL
+  UBSAN_MEMBER_CALL,
+  UBSAN_CTOR_CALL
 };
 
 /* This controls how ubsan prints types.  Used in ubsan_type_descriptor.  */
@@ -43,8 +44,8 @@ struct ubsan_mismatch_data {
   tree ckind;
 };
 
-extern void ubsan_expand_bounds_ifn (gimple_stmt_iterator *);
-extern void ubsan_expand_null_ifn (gimple_stmt_iterator);
+extern bool ubsan_expand_bounds_ifn (gimple_stmt_iterator *);
+extern bool ubsan_expand_null_ifn (gimple_stmt_iterator *);
 extern tree ubsan_instrument_unreachable (location_t);
 extern tree ubsan_create_data (const char *, const location_t *,
 			       const struct ubsan_mismatch_data *, ...);
--- gcc/stor-layout.h.jj	2014-07-03 16:35:56.793168667 +0200
+++ gcc/stor-layout.h	2014-07-04 10:58:10.868536849 +0200
@@ -59,6 +59,9 @@ extern void layout_decl (tree, unsigned)
    node, does nothing except for the first time.  */
 extern void layout_type (tree);
 
+/* Return the least alignment in bytes required for type TYPE.  */
+extern unsigned int min_align_of_type (tree);
+
 /* Construct various nodes representing fract or accum data types.  */
 extern tree make_fract_type (int, int, int);
 extern tree make_accum_type (int, int, int);
--- gcc/cp/cp-gimplify.c.jj	2014-07-03 16:35:57.060167265 +0200
+++ gcc/cp/cp-gimplify.c	2014-07-04 14:30:43.912379242 +0200
@@ -1198,6 +1198,27 @@ cp_genericize_r (tree *stmt_p, int *walk
 	*stmt_p = size_one_node;
       return NULL;
     }    
+  else if (flag_sanitize & (SANITIZE_NULL | SANITIZE_ALIGNMENT))
+    {
+      if (TREE_CODE (stmt) == NOP_EXPR
+	  && TREE_CODE (TREE_TYPE (stmt)) == REFERENCE_TYPE)
+	ubsan_maybe_instrument_reference (stmt);
+      else if (TREE_CODE (stmt) == CALL_EXPR)
+	{
+	  tree fn = CALL_EXPR_FN (stmt);
+	  if (fn != NULL_TREE
+	      && !error_operand_p (fn)
+	      && POINTER_TYPE_P (TREE_TYPE (fn))
+	      && TREE_CODE (TREE_TYPE (TREE_TYPE (fn))) == METHOD_TYPE)
+	    {
+	      bool is_ctor
+		= TREE_CODE (fn) == ADDR_EXPR
+		  && TREE_CODE (TREE_OPERAND (fn, 0)) == FUNCTION_DECL
+		  && DECL_CONSTRUCTOR_P (TREE_OPERAND (fn, 0));
+	      ubsan_maybe_instrument_member_call (stmt, is_ctor);
+	    }
+	}
+    }
 
   pointer_set_insert (p_set, *stmt_p);
 
--- gcc/asan.c.jj	2014-07-03 16:35:57.399165520 +0200
+++ gcc/asan.c	2014-07-04 11:59:58.173638106 +0200
@@ -2749,21 +2749,25 @@ pass_sanopt::execute (function *fun)
   FOR_EACH_BB_FN (bb, fun)
     {
       gimple_stmt_iterator gsi;
-      for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
+      for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); )
 	{
 	  gimple stmt = gsi_stmt (gsi);
+	  bool no_next = false;
 
 	  if (!is_gimple_call (stmt))
-	    continue;
+	    {
+	      gsi_next (&gsi);
+	      continue;
+	    }
 
 	  if (gimple_call_internal_p (stmt))
 	    switch (gimple_call_internal_fn (stmt))
 	      {
 	      case IFN_UBSAN_NULL:
-		ubsan_expand_null_ifn (gsi);
+		no_next = ubsan_expand_null_ifn (&gsi);
 		break;
 	      case IFN_UBSAN_BOUNDS:
-		ubsan_expand_bounds_ifn (&gsi);
+		no_next = ubsan_expand_bounds_ifn (&gsi);
 		break;
 	      default:
 		break;
@@ -2776,9 +2780,8 @@ pass_sanopt::execute (function *fun)
 	      fprintf (dump_file, "\n");
 	    }
 
-	  /* ubsan_expand_bounds_ifn might move us to the end of the BB.  */
-	  if (gsi_end_p (gsi))
-	    break;
+	  if (!no_next)
+	    gsi_next (&gsi);
 	}
     }
   return 0;
--- gcc/ubsan.c.jj	2014-07-03 16:35:56.974167707 +0200
+++ gcc/ubsan.c	2014-07-04 16:40:26.091823514 +0200
@@ -49,6 +49,7 @@ along with GCC; see the file COPYING3.
 #include "intl.h"
 #include "realmpfr.h"
 #include "dfp.h"
+#include "builtins.h"
 
 /* Map from a tree to a VAR_DECL tree.  */
 
@@ -586,7 +587,7 @@ is_ubsan_builtin_p (tree t)
 
 /* Expand the UBSAN_BOUNDS special builtin function.  */
 
-void
+bool
 ubsan_expand_bounds_ifn (gimple_stmt_iterator *gsi)
 {
   gimple stmt = gsi_stmt (*gsi);
@@ -645,21 +646,49 @@ ubsan_expand_bounds_ifn (gimple_stmt_ite
 
   /* Point GSI to next logical statement.  */
   *gsi = gsi_start_bb (fallthru_bb);
+  return true;
 }
 
 /* Expand UBSAN_NULL internal call.  */
 
-void
-ubsan_expand_null_ifn (gimple_stmt_iterator gsi)
+bool
+ubsan_expand_null_ifn (gimple_stmt_iterator *gsip)
 {
+  gimple_stmt_iterator gsi = *gsip;
   gimple stmt = gsi_stmt (gsi);
   location_t loc = gimple_location (stmt);
-  gcc_assert (gimple_call_num_args (stmt) == 2);
+  gcc_assert (gimple_call_num_args (stmt) == 3);
   tree ptr = gimple_call_arg (stmt, 0);
   tree ckind = gimple_call_arg (stmt, 1);
+  tree align = gimple_call_arg (stmt, 2);
+  tree check_align = NULL_TREE;
+  bool check_null;
 
   basic_block cur_bb = gsi_bb (gsi);
 
+  gimple g;
+  if (!integer_zerop (align))
+    {
+      unsigned int ptralign = get_pointer_alignment (ptr) / BITS_PER_UNIT;
+      if (compare_tree_int (align, ptralign) == 1)
+	{
+	  check_align = make_ssa_name (pointer_sized_int_node, NULL);
+	  g = gimple_build_assign_with_ops (NOP_EXPR, check_align,
+					    ptr, NULL_TREE);
+	  gimple_set_location (g, loc);
+	  gsi_insert_before (&gsi, g, GSI_SAME_STMT);
+	}
+    }
+  check_null = (flag_sanitize & SANITIZE_NULL) != 0;
+
+  if (check_align == NULL_TREE && !check_null)
+    {
+      gsi_remove (gsip, true);
+      /* Unlink the UBSAN_NULLs vops before replacing it.  */
+      unlink_stmt_vdef (stmt);
+      return true;
+    }
+
   /* Split the original block holding the pointer dereference.  */
   edge e = split_block (cur_bb, stmt);
 
@@ -689,12 +718,11 @@ ubsan_expand_null_ifn (gimple_stmt_itera
 
   /* Update dominance info for the newly created then_bb; note that
      fallthru_bb's dominance info has already been updated by
-     split_bock.  */
+     split_block.  */
   if (dom_info_available_p (CDI_DOMINATORS))
     set_immediate_dominator (CDI_DOMINATORS, then_bb, cond_bb);
 
   /* Put the ubsan builtin call into the newly created BB.  */
-  gimple g;
   if (flag_sanitize_undefined_trap_on_error)
     g = gimple_build_call (builtin_decl_implicit (BUILT_IN_TRAP), 0);
   else
@@ -705,54 +733,115 @@ ubsan_expand_null_ifn (gimple_stmt_itera
 	  : BUILT_IN_UBSAN_HANDLE_TYPE_MISMATCH_ABORT;
       tree fn = builtin_decl_implicit (bcode);
       const struct ubsan_mismatch_data m
-	= { build_zero_cst (pointer_sized_int_node), ckind };
+	= { align, fold_convert (unsigned_char_type_node, ckind) };
       tree data
 	= ubsan_create_data ("__ubsan_null_data", &loc, &m,
-			     ubsan_type_descriptor (TREE_TYPE (ptr),
+			     ubsan_type_descriptor (TREE_TYPE (ckind),
 						    UBSAN_PRINT_POINTER),
 			     NULL_TREE);
       data = build_fold_addr_expr_loc (loc, data);
       g = gimple_build_call (fn, 2, data,
-			     build_zero_cst (pointer_sized_int_node));
+			     check_align ? check_align
+			     : build_zero_cst (pointer_sized_int_node));
     }
-  gimple_set_location (g, loc);
   gimple_stmt_iterator gsi2 = gsi_start_bb (then_bb);
+  gimple_set_location (g, loc);
   gsi_insert_after (&gsi2, g, GSI_NEW_STMT);
 
   /* Unlink the UBSAN_NULLs vops before replacing it.  */
   unlink_stmt_vdef (stmt);
 
-  g = gimple_build_cond (EQ_EXPR, ptr, build_int_cst (TREE_TYPE (ptr), 0),
-			 NULL_TREE, NULL_TREE);
-  gimple_set_location (g, loc);
+  if (check_null)
+    {
+      g = gimple_build_cond (EQ_EXPR, ptr, build_int_cst (TREE_TYPE (ptr), 0),
+			     NULL_TREE, NULL_TREE);
+      gimple_set_location (g, loc);
 
-  /* Replace the UBSAN_NULL with a GIMPLE_COND stmt.  */
-  gsi_replace (&gsi, g, false);
-}
+      /* Replace the UBSAN_NULL with a GIMPLE_COND stmt.  */
+      gsi_replace (&gsi, g, false);
+    }
 
-/* Instrument a member call.  We check whether 'this' is NULL.  */
+  if (check_align)
+    {
+      if (check_null)
+	{
+	  /* Split the block with the condition again.  */
+	  e = split_block (cond_bb, stmt);
+	  basic_block cond1_bb = e->src;
+	  basic_block cond2_bb = e->dest;
+
+	  /* Make an edge coming from the 'cond1 block' into the 'then block';
+	     this edge is unlikely taken, so set up the probability
+	     accordingly.  */
+	  e = make_edge (cond1_bb, then_bb, EDGE_TRUE_VALUE);
+	  e->probability = PROB_VERY_UNLIKELY;
+
+	  /* Set up the fallthrough basic block.  */
+	  e = find_edge (cond1_bb, cond2_bb);
+	  e->flags = EDGE_FALSE_VALUE;
+	  e->count = cond1_bb->count;
+	  e->probability = REG_BR_PROB_BASE - PROB_VERY_UNLIKELY;
 
-static void
-instrument_member_call (gimple_stmt_iterator *iter)
-{
-  tree this_parm = gimple_call_arg (gsi_stmt (*iter), 0);
-  tree kind = build_int_cst (unsigned_char_type_node, UBSAN_MEMBER_CALL);
-  gimple g = gimple_build_call_internal (IFN_UBSAN_NULL, 2, this_parm, kind);
-  gimple_set_location (g, gimple_location (gsi_stmt (*iter)));
-  gsi_insert_before (iter, g, GSI_SAME_STMT);
+	  /* Update dominance info.  */
+	  if (dom_info_available_p (CDI_DOMINATORS))
+	    {
+	      set_immediate_dominator (CDI_DOMINATORS, fallthru_bb, cond1_bb);
+	      set_immediate_dominator (CDI_DOMINATORS, then_bb, cond1_bb);
+	    }
+
+	  gsi2 = gsi_start_bb (cond2_bb);
+	}
+
+      tree mask = build_int_cst (pointer_sized_int_node,
+				 tree_to_uhwi (align) - 1);
+      g = gimple_build_assign_with_ops (BIT_AND_EXPR,
+					make_ssa_name (pointer_sized_int_node,
+						       NULL),
+					check_align, mask);
+      gimple_set_location (g, loc);
+      if (check_null)
+	gsi_insert_after (&gsi2, g, GSI_NEW_STMT);
+      else
+	gsi_insert_before (&gsi, g, GSI_SAME_STMT);
+
+      g = gimple_build_cond (NE_EXPR, gimple_assign_lhs (g),
+			     build_int_cst (pointer_sized_int_node, 0),
+			     NULL_TREE, NULL_TREE);
+      gimple_set_location (g, loc);
+      if (check_null)
+	gsi_insert_after (&gsi2, g, GSI_NEW_STMT);
+      else
+	/* Replace the UBSAN_NULL with a GIMPLE_COND stmt.  */
+	gsi_replace (&gsi, g, false);
+    }
+  return false;
 }
 
-/* Instrument a memory reference.  T is the pointer, IS_LHS says
+/* Instrument a memory reference.  BASE is the base of MEM, IS_LHS says
    whether the pointer is on the left hand side of the assignment.  */
 
 static void
-instrument_mem_ref (tree t, gimple_stmt_iterator *iter, bool is_lhs)
+instrument_mem_ref (tree mem, tree base, gimple_stmt_iterator *iter,
+		    bool is_lhs)
 {
   enum ubsan_null_ckind ikind = is_lhs ? UBSAN_STORE_OF : UBSAN_LOAD_OF;
-  if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (TREE_TYPE (t))))
+  unsigned int align = 0;
+  if (flag_sanitize & SANITIZE_ALIGNMENT)
+    {
+      align = min_align_of_type (TREE_TYPE (base));
+      if (align <= 1)
+	align = 0;
+    }
+  if (align == 0 && (flag_sanitize & SANITIZE_NULL) == 0)
+    return;
+  tree t = TREE_OPERAND (base, 0);
+  if (!POINTER_TYPE_P (TREE_TYPE (t)))
+    return;
+  if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (TREE_TYPE (t))) && mem != base)
     ikind = UBSAN_MEMBER_ACCESS;
-  tree kind = build_int_cst (unsigned_char_type_node, ikind);
-  gimple g = gimple_build_call_internal (IFN_UBSAN_NULL, 2, t, kind);
+  tree kind = build_int_cst (TREE_TYPE (t), ikind);
+  tree alignt = build_int_cst (pointer_sized_int_node, align);
+  gimple g = gimple_build_call_internal (IFN_UBSAN_NULL, 3, t, kind, alignt);
   gimple_set_location (g, gimple_location (gsi_stmt (*iter)));
   gsi_insert_before (iter, g, GSI_SAME_STMT);
 }
@@ -764,15 +853,11 @@ instrument_null (gimple_stmt_iterator gs
 {
   gimple stmt = gsi_stmt (gsi);
   tree t = is_lhs ? gimple_get_lhs (stmt) : gimple_assign_rhs1 (stmt);
-  t = get_base_address (t);
-  const enum tree_code code = TREE_CODE (t);
+  tree base = get_base_address (t);
+  const enum tree_code code = TREE_CODE (base);
   if (code == MEM_REF
-      && TREE_CODE (TREE_OPERAND (t, 0)) == SSA_NAME)
-    instrument_mem_ref (TREE_OPERAND (t, 0), &gsi, is_lhs);
-  else if (code == ADDR_EXPR
-	   && POINTER_TYPE_P (TREE_TYPE (t))
-	   && TREE_CODE (TREE_TYPE (TREE_TYPE (t))) == METHOD_TYPE)
-    instrument_member_call (&gsi);
+      && TREE_CODE (TREE_OPERAND (base, 0)) == SSA_NAME)
+    instrument_mem_ref (t, base, &gsi, is_lhs);
 }
 
 /* Build an ubsan builtin call for the signed-integer-overflow
@@ -1148,7 +1233,8 @@ public:
   virtual bool gate (function *)
     {
       return flag_sanitize & (SANITIZE_NULL | SANITIZE_SI_OVERFLOW
-			      | SANITIZE_BOOL | SANITIZE_ENUM)
+			      | SANITIZE_BOOL | SANITIZE_ENUM
+			      | SANITIZE_ALIGNMENT)
 	     && current_function_decl != NULL_TREE
 	     && !lookup_attribute ("no_sanitize_undefined",
 				   DECL_ATTRIBUTES (current_function_decl));
@@ -1181,7 +1267,7 @@ pass_ubsan::execute (function *fun)
 	      && is_gimple_assign (stmt))
 	    instrument_si_overflow (gsi);
 
-	  if (flag_sanitize & SANITIZE_NULL)
+	  if (flag_sanitize & (SANITIZE_NULL | SANITIZE_ALIGNMENT))
 	    {
 	      if (gimple_store_p (stmt))
 		instrument_null (gsi, true);
--- gcc/stor-layout.c.jj	2014-07-03 16:35:56.750168857 +0200
+++ gcc/stor-layout.c	2014-07-04 10:58:10.918536587 +0200
@@ -2389,6 +2389,27 @@ layout_type (tree type)
     gcc_assert (!TYPE_ALIAS_SET_KNOWN_P (type));
 }
 
+/* Return the least alignment required for type TYPE.  */
+
+unsigned int
+min_align_of_type (tree type)
+{
+  unsigned int align = TYPE_ALIGN (type);
+  align = MIN (align, BIGGEST_ALIGNMENT);
+#ifdef BIGGEST_FIELD_ALIGNMENT
+  align = MIN (align, BIGGEST_FIELD_ALIGNMENT);
+#endif
+  unsigned int field_align = align;
+#ifdef ADJUST_FIELD_ALIGN
+  tree field = build_decl (UNKNOWN_LOCATION, FIELD_DECL, NULL_TREE,
+			   type);
+  field_align = ADJUST_FIELD_ALIGN (field, field_align);
+  ggc_free (field);
+#endif
+  align = MIN (align, field_align);
+  return align / BITS_PER_UNIT;
+}
+
 /* Vector types need to re-check the target flags each time we report
    the machine mode.  We need to do this because attribute target can
    change the result of vector_mode_supported_p and have_regs_of_mode
--- gcc/flag-types.h.jj	2014-07-03 16:35:57.392165557 +0200
+++ gcc/flag-types.h	2014-07-04 10:58:10.918536587 +0200
@@ -231,10 +231,11 @@ enum sanitize_code {
   SANITIZE_FLOAT_DIVIDE = 1 << 12,
   SANITIZE_FLOAT_CAST = 1 << 13,
   SANITIZE_BOUNDS = 1 << 14,
+  SANITIZE_ALIGNMENT = 1 << 17,
   SANITIZE_UNDEFINED = SANITIZE_SHIFT | SANITIZE_DIVIDE | SANITIZE_UNREACHABLE
 		       | SANITIZE_VLA | SANITIZE_NULL | SANITIZE_RETURN
 		       | SANITIZE_SI_OVERFLOW | SANITIZE_BOOL | SANITIZE_ENUM
-		       | SANITIZE_BOUNDS,
+		       | SANITIZE_BOUNDS | SANITIZE_ALIGNMENT,
   SANITIZE_NONDEFAULT = SANITIZE_FLOAT_DIVIDE | SANITIZE_FLOAT_CAST
 };
 
--- gcc/doc/invoke.texi.jj	2014-07-03 16:35:58.062162110 +0200
+++ gcc/doc/invoke.texi	2014-07-04 16:43:25.377930768 +0200
@@ -5426,7 +5426,8 @@ instead.
 This option enables pointer checking.  Particularly, the application
 built with this option turned on will issue an error message when it
 tries to dereference a NULL pointer, or if a reference (possibly an
-rvalue reference) is bound to a NULL pointer.
+rvalue reference) is bound to a NULL pointer, or if a method is invoked
+on an object pointed by a NULL pointer.
 
 @item -fsanitize=return
 @opindex fsanitize=return
@@ -5453,6 +5454,13 @@ This option enables instrumentation of a
 accesses are detected.  Flexible array members and initializers of variables
 with static storage are not instrumented.
 
+@item -fsanitize=alignment
+@opindex fsanitize=alignment
+
+This option enables checking of alignment of pointers when they are
+dereferenced, or when a reference is bound to insufficiently aligned target,
+or when a method or constructor is invoked on insufficiently aligned object.
+
 @item -fsanitize=float-divide-by-zero
 @opindex fsanitize=float-divide-by-zero
 Detect floating-point division by zero.  Unlike other similar options,
--- gcc/testsuite/g++.dg/ubsan/attrib-1.C.jj	2014-07-04 16:14:02.868473415 +0200
+++ gcc/testsuite/g++.dg/ubsan/attrib-1.C	2014-07-04 16:16:56.328621864 +0200
@@ -0,0 +1,27 @@
+// { dg-do compile }
+// { dg-options "-fsanitize=undefined -Wall -Wno-unused-variable -std=c++11" }
+
+typedef const long int L;
+
+__attribute__((no_sanitize_undefined)) void
+foo (int *p, L *l)
+{
+  int &r = *p;
+  auto &r2 = *p;
+  L &lr = *l;
+  auto &&r3 = *p;
+}
+
+struct U
+{
+  int a;
+  void foo () {}
+};
+
+__attribute__((no_sanitize_undefined)) void
+bar (U *p)
+{
+  p->foo ();
+}
+
+// { dg-final { scan-assembler-not "__ubsan_handle" } }
--- gcc/testsuite/g++.dg/ubsan/null-1.C.jj	2014-07-04 10:58:10.921536572 +0200
+++ gcc/testsuite/g++.dg/ubsan/null-1.C	2014-07-04 12:55:48.281143812 +0200
@@ -0,0 +1,30 @@
+// { dg-do run }
+// { dg-options "-fsanitize=null -Wall -Wno-unused-variable -std=c++11" }
+
+typedef const long int L;
+
+int
+main (void)
+{
+  int *p = 0;
+  L *l = 0;
+
+  int &r = *p;
+  auto &r2 = *p;
+  L &lr = *l;
+
+  // Try an rvalue reference.
+  auto &&r3 = *p;
+
+  // Don't evaluate the reference initializer twice.
+  int i = 1;
+  int *q = &i;
+  int &qr = ++*q;
+  if (i != 2)
+    __builtin_abort ();
+}
+
+// { dg-output "reference binding to null pointer of type 'int'(\n|\r\n|\r)" }
+// { dg-output "\[^\n\r]*reference binding to null pointer of type 'int'(\n|\r\n|\r)" }
+// { dg-output "\[^\n\r]*reference binding to null pointer of type 'const L'(\n|\r\n|\r)" }
+// { dg-output "\[^\n\r]*reference binding to null pointer of type 'int'(\n|\r\n|\r)" }
--- gcc/testsuite/g++.dg/ubsan/align-2.C.jj	2014-07-04 11:03:58.707738888 +0200
+++ gcc/testsuite/g++.dg/ubsan/align-2.C	2014-07-04 15:54:08.947361535 +0200
@@ -0,0 +1,45 @@
+// Limit this to known non-strict alignment targets.
+// { dg-do run { target { i?86-*-linux* x86_64-*-linux* } } }
+// { dg-options "-fsanitize=alignment -Wall -Wno-unused-variable -std=c++11" }
+
+typedef const long int L;
+struct S { long int l; char buf[1 + sizeof (int) + sizeof (L)]; } s;
+struct T { char a; int b; long int c; } __attribute__((packed));
+struct U { long int a; struct T b; } u;
+
+int
+main (void)
+{
+  int *p = (int *) &s.buf[1];
+  L *l = (L *) &s.buf[1 + sizeof(int)];
+
+  int &r = *p;
+  auto &r2 = *p;
+  L &lr = *l;
+
+  // Try an rvalue reference.
+  auto &&r3 = *p;
+
+  // Don't evaluate the reference initializer twice.
+  int i = 1;
+  int *q = &i;
+  int &qr = ++*q;
+  if (i != 2)
+    __builtin_abort ();
+
+  int *s = &u.b.b;
+  L *t = &u.b.c;
+  int &r4 = *s;
+  auto &r5 = *s;
+  L &lr2 = *t;
+  auto &&r6 = *s;
+}
+
+// { dg-output "\.C:16:\[0-9]*:\[\^\n\r]*reference binding to misaligned address 0x\[0-9a-fA-F]* for type 'int', which requires 4 byte alignment.*" }
+// { dg-output "\.C:17:\[0-9]*:\[\^\n\r]*reference binding to misaligned address 0x\[0-9a-fA-F]* for type 'int', which requires 4 byte alignment.*" }
+// { dg-output "\.C:18:\[0-9]*:\[\^\n\r]*reference binding to misaligned address 0x\[0-9a-fA-F]* for type 'const L', which requires \[48] byte alignment.*" }
+// { dg-output "\.C:21:\[0-9]*:\[\^\n\r]*reference binding to misaligned address 0x\[0-9a-fA-F]* for type 'int', which requires 4 byte alignment.*" }
+// { dg-output "\.C:32:\[0-9]*:\[\^\n\r]*reference binding to misaligned address 0x\[0-9a-fA-F]* for type 'int', which requires 4 byte alignment.*" }
+// { dg-output "\.C:33:\[0-9]*:\[\^\n\r]*reference binding to misaligned address 0x\[0-9a-fA-F]* for type 'int', which requires 4 byte alignment.*" }
+// { dg-output "\.C:34:\[0-9]*:\[\^\n\r]*reference binding to misaligned address 0x\[0-9a-fA-F]* for type 'const L', which requires \[48] byte alignment.*" }
+// { dg-output "\.C:35:\[0-9]*:\[\^\n\r]*reference binding to misaligned address 0x\[0-9a-fA-F]* for type 'int', which requires 4 byte alignment" }
--- gcc/testsuite/g++.dg/ubsan/null-2.C.jj	2014-07-04 16:07:46.082297197 +0200
+++ gcc/testsuite/g++.dg/ubsan/null-2.C	2014-07-04 16:12:52.471818230 +0200
@@ -0,0 +1,39 @@
+// Limit this to known non-strict alignment targets.
+// { dg-do run { target { i?86-*-linux* x86_64-*-linux* } } }
+// { dg-options "-fsanitize=null -Wall -Wno-unused-variable -std=c++11" }
+
+#include <new>
+
+struct U
+{
+  int a;
+  void foo () {}
+};
+struct V
+{
+  V () {};
+  ~V () {};
+  int a;
+  void foo () {}
+  static void bar () {}
+};
+struct S { long int l; char buf[1 + sizeof (U) + 2 * sizeof (V)]; } s;
+
+int
+main (void)
+{
+  U *p = 0;
+  p->foo ();
+  char *q = 0;
+  V *u = new (q) V;
+  u->~V ();
+  V *v = new (q) V;
+  v->foo ();
+  v->bar ();	// We don't instrument this right now.
+  v->~V ();
+}
+
+// { dg-output "\.C:26:\[0-9]*:\[\^\n\r]*member call on null pointer of type 'struct U'.*" }
+// { dg-output "\.C:29:\[0-9]*:\[\^\n\r]*member call on null pointer of type 'struct V'.*" }
+// { dg-output "\.C:31:\[0-9]*:\[\^\n\r]*member call on null pointer of type 'struct V'.*" }
+// { dg-output "\.C:33:\[0-9]*:\[\^\n\r]*member call on null pointer of type 'struct V'" }
--- gcc/testsuite/g++.dg/ubsan/align-3.C.jj	2014-07-04 15:56:31.837668592 +0200
+++ gcc/testsuite/g++.dg/ubsan/align-3.C	2014-07-04 15:56:09.000000000 +0200
@@ -0,0 +1,45 @@
+// Limit this to known non-strict alignment targets.
+// { dg-do run { target { i?86-*-linux* x86_64-*-linux* } } }
+// { dg-options "-fsanitize=alignment -Wall -Wno-unused-variable -std=c++11" }
+
+#include <new>
+
+struct U
+{
+  int a;
+  void foo () {}
+};
+struct V
+{
+  V () : a (0) {};
+  ~V () { a = 0; };
+  int a;
+  void foo () {}
+  static void bar () {}
+};
+struct S { long int l; char buf[1 + sizeof (U) + 2 * sizeof (V)]; } s;
+
+int
+main (void)
+{
+  U *p = (U *) &s.buf[1];
+  p->foo ();
+  char *q = &s.buf[1 + sizeof (U)];
+  V *u = new (q) V;
+  u->a = 1;
+  u->~V ();
+  V *v = new (&s.buf[1 + sizeof (U) + sizeof (V)]) V;
+  v->foo ();
+  v->bar ();	// We don't instrument this right now.
+  v->~V ();
+}
+
+// { dg-output "\.C:26:\[0-9]*:\[\^\n\r]*member call on misaligned address 0x\[0-9a-fA-F]* for type 'struct U', which requires 4 byte alignment.*" }
+// { dg-output "\.C:28:\[0-9]*:\[\^\n\r]*constructor call on misaligned address 0x\[0-9a-fA-F]* for type 'struct V', which requires 4 byte alignment.*" }
+// { dg-output "\.C:14:\[0-9]*:\[\^\n\r]*member access within misaligned address 0x\[0-9a-fA-F]* for type 'struct V', which requires 4 byte alignment.*" }
+// { dg-output "\.C:29:\[0-9]*:\[\^\n\r]*member access within misaligned address 0x\[0-9a-fA-F]* for type 'struct V', which requires 4 byte alignment.*" }
+// { dg-output "\.C:30:\[0-9]*:\[\^\n\r]*member call on misaligned address 0x\[0-9a-fA-F]* for type 'struct V', which requires 4 byte alignment.*" }
+// { dg-output "\.C:15:\[0-9]*:\[\^\n\r]*member access within misaligned address 0x\[0-9a-fA-F]* for type 'struct V', which requires 4 byte alignment.*" }
+// { dg-output "\.C:31:\[0-9]*:\[\^\n\r]*constructor call on misaligned address 0x\[0-9a-fA-F]* for type 'struct V', which requires 4 byte alignment.*" }
+// { dg-output "\.C:32:\[0-9]*:\[\^\n\r]*member call on misaligned address 0x\[0-9a-fA-F]* for type 'struct V', which requires 4 byte alignment.*" }
+// { dg-output "\.C:34:\[0-9]*:\[\^\n\r]*member call on misaligned address 0x\[0-9a-fA-F]* for type 'struct V', which requires 4 byte alignment" }
--- gcc/testsuite/g++.dg/ubsan/align-1.C.jj	2014-07-04 11:03:10.820985959 +0200
+++ gcc/testsuite/g++.dg/ubsan/align-1.C	2014-07-04 12:55:31.873220888 +0200
@@ -0,0 +1,27 @@
+// { dg-do run }
+// { dg-options "-fsanitize=alignment -Wall -Wno-unused-variable -std=c++11" }
+
+typedef const long int L;
+int a = 1;
+L b = 2;
+
+int
+main (void)
+{
+  int *p = &a;
+  L *l = &b;
+
+  int &r = *p;
+  auto &r2 = *p;
+  L &lr = *l;
+
+  // Try an rvalue reference.
+  auto &&r3 = *p;
+
+  // Don't evaluate the reference initializer twice.
+  int i = 1;
+  int *q = &i;
+  int &qr = ++*q;
+  if (i != 2)
+    __builtin_abort ();
+}
--- gcc/testsuite/c-c++-common/ubsan/align-4.c.jj	2014-07-04 10:58:10.922536566 +0200
+++ gcc/testsuite/c-c++-common/ubsan/align-4.c	2014-07-04 10:58:10.922536566 +0200
@@ -0,0 +1,14 @@
+/* Limit this to known non-strict alignment targets.  */
+/* { dg-do run { target { i?86-*-linux* x86_64-*-linux* } } } */
+/* { dg-options "-fsanitize=null,alignment" } */
+
+#include "align-2.c"
+
+/* { dg-output "\.c:(14|15):\[0-9]*: \[^\n\r]*load of misaligned address 0x\[0-9a-fA-F]* for type 'int', which requires 4 byte alignment.*" } */
+/* { dg-output "\[^\n\r]*\.c:16:\[0-9]*: \[^\n\r]*load of misaligned address 0x\[0-9a-fA-F]* for type 'long long int', which requires \[48] byte alignment.*" } */
+/* { dg-output "\[^\n\r]*\.c:(13|16):\[0-9]*: \[^\n\r]*store to misaligned address 0x\[0-9a-fA-F]* for type 'int', which requires 4 byte alignment.*" } */
+/* { dg-output "\[^\n\r]*\.c:23:\[0-9]*: \[^\n\r]*member access within misaligned address 0x\[0-9a-fA-F]* for type 'struct S', which requires \[48] byte alignment.*" } */
+/* { dg-output "\[^\n\r]*\.c:(29|30):\[0-9]*: \[^\n\r]*member access within misaligned address 0x\[0-9a-fA-F]* for type 'struct S', which requires \[48] byte alignment.*" } */
+/* { dg-output "\[^\n\r]*\.c:30:\[0-9]*: \[^\n\r]*member access within misaligned address 0x\[0-9a-fA-F]* for type 'struct S', which requires \[48] byte alignment.*" } */
+/* { dg-output "\[^\n\r]*\.c:31:\[0-9]*: \[^\n\r]*member access within misaligned address 0x\[0-9a-fA-F]* for type 'struct S', which requires \[48] byte alignment.*" } */
+/* { dg-output "\[^\n\r]*\.c:37:\[0-9]*: \[^\n\r]*load of misaligned address 0x\[0-9a-fA-F]* for type 'long long int', which requires \[48] byte alignment" } */
--- gcc/testsuite/c-c++-common/ubsan/align-1.c.jj	2014-07-04 10:58:10.922536566 +0200
+++ gcc/testsuite/c-c++-common/ubsan/align-1.c	2014-07-04 10:58:10.922536566 +0200
@@ -0,0 +1,41 @@
+/* { dg-do run } */
+/* { dg-options "-fsanitize=undefined -fno-sanitize-recover" } */
+
+struct S { int a; char b; long long c; short d[10]; };
+struct T { char a; long long b; };
+struct U { char a; int b; int c; long long d; struct S e; struct T f; };
+struct V { long long a; struct S b; struct T c; struct U u; } v;
+
+__attribute__((noinline, noclone)) void
+f1 (int *p, int *q, char *r, long long *s)
+{
+  *p = *q + *r + *s;
+}
+
+
+__attribute__((noinline, noclone)) int
+f2 (struct S *p)
+{
+  return p->a;
+}
+
+__attribute__((noinline, noclone)) long long
+f3 (struct S *p, int i)
+{
+  return p->c + p->d[1] + p->d[i];
+}
+
+__attribute__((noinline, noclone)) long long
+f4 (long long *p)
+{
+  return *p;
+}
+
+int
+main ()
+{
+  f1 (&v.u.b, &v.u.c, &v.u.a, &v.u.d);
+  if (f2 (&v.u.e) + f3 (&v.u.e, 4) + f4 (&v.u.f.b) != 0)
+    __builtin_abort ();
+  return 0;
+}
--- gcc/testsuite/c-c++-common/ubsan/attrib-4.c.jj	2014-07-04 10:58:10.922536566 +0200
+++ gcc/testsuite/c-c++-common/ubsan/attrib-4.c	2014-07-04 10:58:10.922536566 +0200
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "-fsanitize=undefined" } */
+
+/* Test that we don't instrument functions marked with
+   no_sanitize_undefined attribute.  */
+
+struct S { int a[16]; };
+
+__attribute__((no_sanitize_undefined)) long long
+foo (int *a, long long *b, struct S *c)
+{
+  return a[1] + *b + c->a[a[0]];
+}
+
+/* { dg-final { scan-assembler-not "__ubsan_handle" } } */
--- gcc/testsuite/c-c++-common/ubsan/align-2.c.jj	2014-07-04 10:58:10.951536415 +0200
+++ gcc/testsuite/c-c++-common/ubsan/align-2.c	2014-07-04 12:08:46.122994090 +0200
@@ -0,0 +1,56 @@
+/* Limit this to known non-strict alignment targets.  */
+/* { dg-do run { target { i?86-*-linux* x86_64-*-linux* } } } */
+/* { dg-options "-fsanitize=alignment" } */
+
+struct S { int a; char b; long long c; short d[10]; };
+struct T { char a; long long b; };
+struct U { char a; int b; int c; long long d; struct S e; struct T f; } __attribute__((packed));
+struct V { long long a; struct S b; struct T c; struct U u; } v;
+
+__attribute__((noinline, noclone)) void
+f1 (int *p, int *q, char *r, long long *s)
+{
+  *p =
+      *q
+      + *r
+      + *s;
+}
+
+
+__attribute__((noinline, noclone)) int
+f2 (struct S *p)
+{
+  return p->a;
+}
+
+__attribute__((noinline, noclone)) long long
+f3 (struct S *p, int i)
+{
+  return p->c
+	 + p->d[1]
+	 + p->d[i];
+}
+
+__attribute__((noinline, noclone)) long long
+f4 (long long *p)
+{
+  return *p;
+}
+
+int
+main ()
+{
+  f1 (&v.u.b, &v.u.c, &v.u.a, &v.u.d);
+  if (f2 (&v.u.e) + f3 (&v.u.e, 4) + f4 (&v.u.f.b) != 0)
+    __builtin_abort ();
+  return 0;
+}
+
+/* { dg-output "\.c:(14|15):\[0-9]*: \[^\n\r]*load of misaligned address 0x\[0-9a-fA-F]* for type 'int', which requires 4 byte alignment.*" } */
+/* { dg-output "\.c:16:\[0-9]*: \[^\n\r]*load of misaligned address 0x\[0-9a-fA-F]* for type 'long long int', which requires \[48] byte alignment.*" } */
+/* { dg-output "\.c:(13|16):\[0-9]*: \[^\n\r]*store to misaligned address 0x\[0-9a-fA-F]* for type 'int', which requires 4 byte alignment.*" } */
+/* { dg-output "\.c:23:\[0-9]*: \[^\n\r]*member access within misaligned address 0x\[0-9a-fA-F]* for type 'struct S', which requires \[48] byte alignment.*" } */
+/* { dg-output "\.c:(29|30):\[0-9]*: \[^\n\r]*member access within misaligned address 0x\[0-9a-fA-F]* for type 'struct S', which requires \[48] byte alignment.*" } */
+/* { dg-output "\.c:30:\[0-9]*: \[^\n\r]*member access within misaligned address 0x\[0-9a-fA-F]* for type 'struct S', which requires \[48] byte alignment.*" } */
+/* { dg-output "\.c:31:\[0-9]*: \[^\n\r]*member access within misaligned address 0x\[0-9a-fA-F]* for type 'struct S', which requires \[48] byte alignment.*" } */
+/* { dg-output "\.c:37:\[0-9]*: \[^\n\r]*load of misaligned address 0x\[0-9a-fA-F]* for type 'long long int', which requires \[48] byte alignment" } */
--- gcc/testsuite/c-c++-common/ubsan/align-5.c.jj	2014-07-04 10:58:10.951536415 +0200
+++ gcc/testsuite/c-c++-common/ubsan/align-5.c	2014-07-04 10:58:10.951536415 +0200
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "-fno-sanitize=null -fsanitize=alignment -O2" } */
+/* Check that when optimizing if we know the alignment is right
+   and we are not doing -fsanitize=null instrumentation we don't
+   instrument the alignment check.  */
+
+__attribute__((noinline, noclone)) int
+foo (char *p)
+{
+  p = (char *) __builtin_assume_aligned (p, __alignof__(int));
+  int *q = (int *) p;
+  return *q;
+}
+
+/* { dg-final { scan-assembler-not "__ubsan_handle" } } */
--- gcc/testsuite/c-c++-common/ubsan/align-3.c.jj	2014-07-04 10:58:10.951536415 +0200
+++ gcc/testsuite/c-c++-common/ubsan/align-3.c	2014-07-04 10:58:10.951536415 +0200
@@ -0,0 +1,66 @@
+/* { dg-do run } */
+/* { dg-options "-fsanitize=undefined -fno-sanitize-recover" } */
+
+int c;
+
+__attribute__((noinline, noclone)) void
+f1 (int *a, char *b)
+{
+  __builtin_memcpy (a, b, sizeof (*a));
+}
+
+__attribute__((noinline, noclone)) void
+f2 (int *a, char *b)
+{
+  __builtin_memcpy (b, a, sizeof (*a));
+}
+
+__attribute__((noinline, noclone)) void
+f3 (char *b)
+{
+  __builtin_memcpy (&c, b, sizeof (c));
+}
+
+__attribute__((noinline, noclone)) void
+f4 (char *b)
+{
+  __builtin_memcpy (b, &c, sizeof (c));
+}
+
+struct T
+{
+  char a;
+  short b;
+  int c;
+  long d;
+  long long e;
+  short f;
+  float g;
+  double h;
+  long double i;
+} __attribute__((packed));
+
+__attribute__((noinline, noclone)) int
+f5 (struct T *p)
+{
+  return p->a + p->b + p->c + p->d + p->e + p->f + p->g + p->h + p->i;
+}
+
+int
+main ()
+{
+  struct S { int a; char b[sizeof (int) + 1]; } s;
+  s.a = 6;
+  f2 (&s.a, &s.b[1]);
+  f1 (&s.a, &s.b[1]);
+  c = s.a + 1;
+  f4 (&s.b[1]);
+  f3 (&s.b[1]);
+  if (c != 7 || s.a != 6)
+    __builtin_abort ();
+  struct U { long long a; long double b; char c; struct T d; } u;
+  __builtin_memset (&u, 0, sizeof (u));
+  if (f5 (&u.d) != 0)
+    __builtin_abort ();
+  return 0;
+}
--- gcc/c-family/c-ubsan.c.jj	2014-07-03 16:35:56.709169077 +0200
+++ gcc/c-family/c-ubsan.c	2014-07-04 16:01:01.822326829 +0200
@@ -31,6 +31,8 @@ along with GCC; see the file COPYING3.
 #include "c-family/c-ubsan.h"
 #include "asan.h"
 #include "internal-fn.h"
+#include "stor-layout.h"
+#include "builtins.h"
 
 /* Instrument division by zero and INT_MIN / -1.  If not instrumenting,
    return NULL_TREE.  */
@@ -350,3 +352,99 @@ ubsan_maybe_instrument_array_ref (tree *
 	}
     }
 }
+
+static tree
+ubsan_maybe_instrument_reference_or_call (location_t loc, tree op, tree type,
+					  enum ubsan_null_ckind ckind)
+{
+  tree orig_op = op;
+  bool instrument = false;
+  unsigned int mina = 0;
+
+  if (current_function_decl == NULL_TREE
+      || lookup_attribute ("no_sanitize_undefined",
+			   DECL_ATTRIBUTES (current_function_decl)))
+    return NULL_TREE;
+
+  if (flag_sanitize & SANITIZE_ALIGNMENT)
+    {
+      mina = min_align_of_type (type);
+      if (mina <= 1)
+	mina = 0;
+    }
+  while ((TREE_CODE (op) == NOP_EXPR
+	  || TREE_CODE (op) == NON_LVALUE_EXPR)
+	 && TREE_CODE (TREE_TYPE (op)) == POINTER_TYPE)
+    op = TREE_OPERAND (op, 0);
+  if (TREE_CODE (op) == NOP_EXPR
+      && TREE_CODE (TREE_TYPE (op)) == REFERENCE_TYPE)
+    {
+      if (mina && mina > min_align_of_type (TREE_TYPE (TREE_TYPE (op))))
+	instrument = true;
+    }
+  else
+    {
+      if ((flag_sanitize & SANITIZE_NULL) && TREE_CODE (op) == ADDR_EXPR)
+	{
+	  bool strict_overflow_p = false;
+	  /* tree_single_nonzero_warnv_p will not return true for non-weak
+	     non-automatic decls with -fno-delete-null-pointer-checks,
+	     which is disabled during -fsanitize=null.  We don't want to
+	     instrument those, just weak vars though.  */
+	  int save_flag_delete_null_pointer_checks
+	    = flag_delete_null_pointer_checks;
+	  flag_delete_null_pointer_checks = 1;
+	  if (!tree_single_nonzero_warnv_p (op, &strict_overflow_p)
+	      || strict_overflow_p)
+	    instrument = true;
+	  flag_delete_null_pointer_checks
+	    = save_flag_delete_null_pointer_checks;
+	}
+      else if (flag_sanitize & SANITIZE_NULL)
+	instrument = true;
+      if (mina && mina > get_pointer_alignment (op) / BITS_PER_UNIT)
+	instrument = true;
+    }
+  if (!instrument)
+    return NULL_TREE;
+  op = save_expr (orig_op);
+  tree kind = build_int_cst (TREE_TYPE (op), ckind);
+  tree align = build_int_cst (pointer_sized_int_node, mina);
+  tree call
+    = build_call_expr_internal_loc (loc, IFN_UBSAN_NULL, void_type_node,
+				    3, op, kind, align);
+  TREE_SIDE_EFFECTS (call) = 1;
+  return fold_build2 (COMPOUND_EXPR, TREE_TYPE (op), call, op);
+}
+
+/* Instrument a NOP_EXPR to REFERENCE_TYPE if needed.  */
+
+void
+ubsan_maybe_instrument_reference (tree stmt)
+{
+  tree op = TREE_OPERAND (stmt, 0);
+  op = ubsan_maybe_instrument_reference_or_call (EXPR_LOCATION (stmt), op,
+						 TREE_TYPE (TREE_TYPE (stmt)),
+						 UBSAN_REF_BINDING);
+  if (op)
+    TREE_OPERAND (stmt, 0) = op;
+}
+
+/* Instrument a CALL_EXPR to a method if needed.  */
+
+void
+ubsan_maybe_instrument_member_call (tree stmt, bool is_ctor)
+{
+  if (call_expr_nargs (stmt) == 0)
+    return;
+  tree op = CALL_EXPR_ARG (stmt, 0);
+  if (op == error_mark_node
+      || !POINTER_TYPE_P (TREE_TYPE (op)))
+    return;
+  op = ubsan_maybe_instrument_reference_or_call (EXPR_LOCATION (stmt), op,
+						 TREE_TYPE (TREE_TYPE (op)),
+						 is_ctor ? UBSAN_CTOR_CALL
+						 : UBSAN_MEMBER_CALL);
+  if (op)
+    CALL_EXPR_ARG (stmt, 0) = op;
+}
--- gcc/c-family/c-common.c.jj	2014-07-03 16:35:56.634169310 +0200
+++ gcc/c-family/c-common.c	2014-07-04 10:58:10.980536264 +0200
@@ -4962,26 +4962,6 @@ c_common_get_alias_set (tree t)
   return -1;
 }
 
-/* Return the least alignment required for type TYPE.  */
-
-unsigned int
-min_align_of_type (tree type)
-{
-  unsigned int align = TYPE_ALIGN (type);
-  align = MIN (align, BIGGEST_ALIGNMENT);
-#ifdef BIGGEST_FIELD_ALIGNMENT
-  align = MIN (align, BIGGEST_FIELD_ALIGNMENT);
-#endif
-  unsigned int field_align = align;
-#ifdef ADJUST_FIELD_ALIGN
-  tree field = build_decl (UNKNOWN_LOCATION, FIELD_DECL, NULL_TREE,
-			   type);
-  field_align = ADJUST_FIELD_ALIGN (field, field_align);
-#endif
-  align = MIN (align, field_align);
-  return align / BITS_PER_UNIT;
-}
-
 /* Compute the value of 'sizeof (TYPE)' or '__alignof__ (TYPE)', where
    the IS_SIZEOF parameter indicates which operator is being applied.
    The COMPLAIN flag controls whether we should diagnose possibly
--- gcc/c-family/c-common.h.jj	2014-07-03 16:35:56.673169184 +0200
+++ gcc/c-family/c-common.h	2014-07-04 10:58:10.989536216 +0200
@@ -762,7 +762,6 @@ extern tree c_wrap_maybe_const (tree, bo
 extern tree c_save_expr (tree);
 extern tree c_common_truthvalue_conversion (location_t, tree);
 extern void c_apply_type_quals_to_decl (int, tree);
-extern unsigned int min_align_of_type (tree);
 extern tree c_sizeof_or_alignof_type (location_t, tree, bool, bool, int);
 extern tree c_alignof_expr (location_t, tree);
 /* Print an error message for invalid operands to arith operation CODE.
--- gcc/c-family/c-ubsan.h.jj	2014-07-03 16:35:56.585169605 +0200
+++ gcc/c-family/c-ubsan.h	2014-07-04 14:34:27.051261627 +0200
@@ -28,5 +28,7 @@ extern tree ubsan_instrument_return (loc
 extern tree ubsan_instrument_bounds (location_t, tree, tree *, bool);
 extern bool ubsan_array_ref_instrumented_p (const_tree);
 extern void ubsan_maybe_instrument_array_ref (tree *, bool);
+extern void ubsan_maybe_instrument_reference (tree);
+extern void ubsan_maybe_instrument_member_call (tree, bool);
 
 #endif  /* GCC_C_UBSAN_H  */

	Jakub


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]