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]

Re: [PATCH] -fsanitize=vptr instrumentation (take 2)


On Mon, Oct 27, 2014 at 05:16:05PM +0100, Jakub Jelinek wrote:
> Here is an updated patch, ok if bootstrap/testing passes (so far just
> checked with
> make -j16 -k check RUNTESTFLAGS='--target_board=unix\{-m32,-m64\} asan.exp tsan.exp ubsan.exp'
> )?

Updated patch that passed bootstrap/regtest on i686-linux.
Only minor changes: ensure during the cp_walk_tree we don't walk same trees
more than once (with SAVE_EXPR resulted in huge compile times), tiny test
cleanups, and making sure __ubsan_vptr_type_cache decl has normal visibility
and is not considered local in shared libraries.

2014-10-28  Jakub Jelinek  <jakub@redhat.com>

	* flag-types.h (enum sanitize_code): Add SANITIZE_VPTR,
	include SANITIZE_VPTR in SANITIZE_UNDEFINED.
	* opts.c (common_handle_option): Add -fsanitize=vptr.
	* sanitizer.def (BUILT_IN_UBSAN_HANDLE_DYNAMIC_TYPE_CACHE_MISS,
	BUILT_IN_UBSAN_HANDLE_DYNAMIC_TYPE_CACHE_MISS_ABORT): New.
	* ubsan.h (enum ubsan_null_ckind): Add UBSAN_DOWNCAST_POINTER,
	UBSAN_DOWNCAST_REFERENCE, UBSAN_UPCAST and UBSAN_CAST_TO_VBASE.
cp/
	* config-lang.in (gtfiles): Add cp/cp-ubsan.c.
	* cp-gimplify.c (cp_genericize_r): Call
	cp_ubsan_maybe_instrument_member_call for member calls and
	cp_ubsan_maybe_instrument_member_access for member accesses.
	(struct cp_ubsan_check_member_access_data): New type.
	(cp_ubsan_check_member_access_r): New function.
	(cp_genericize_tree): Call cp_walk_tree with
	cp_ubsan_check_member_access_r callback for -fsanitize=vptr.
	* cp-tree.h (cp_ubsan_maybe_instrument_member_call,
	cp_ubsan_maybe_instrument_member_access,
	cp_ubsan_maybe_instrument_downcast,
	cp_ubsan_maybe_instrument_cast_to_vbase,
	cp_ubsan_fixup_downcast_instrumentation): New prototypes.
	* cp-ubsan.c: New file.
	* Make-lang.in (CXX_AND_OBJCXX_OBJS): Add cp/cp-ubsan.o.
	* constexpr.c (cxx_eval_call_expression): Handle 4 argument
	BUILT_IN_UBSAN_HANDLE_DYNAMIC_TYPE_CACHE_MISS{,_ABORT}.
	* typeck.c (build_class_member_access_expr): Provide locus
	for COMPONENT_REFs.
	(build_static_cast_1): Instrument downcasts.
	* class.c (build_base_path): For -fsanitize=vptr and !fixed_type_p
	add ubsan instrumentation for virtual_access.
gcc/testsuite/
	* g++.dg/ubsan/vptr-1.C: New test.
	* g++.dg/ubsan/vptr-2.C: New test.
	* g++.dg/ubsan/vptr-3.C: New test.
	* g++.dg/ubsan/vptr-4.C: New test.
	* g++.dg/ubsan/vptr-5.C: New test.
	* g++.dg/ubsan/vptr-6.C: New test.
	* g++.dg/ubsan/vptr-7.C: New test.
	* g++.dg/ubsan/vptr-8.C: New test.
	* g++.dg/ubsan/vptr-9.C: New test.
libsanitizer/
	* ubsan/ubsan_handlers.cc (__ubsan::TypeCheckKinds): Cherry pick
	upstream r219642.

--- gcc/opts.c.jj	2014-10-25 20:46:06.443427738 +0200
+++ gcc/opts.c	2014-10-27 10:48:06.855097104 +0100
@@ -1575,6 +1575,7 @@ common_handle_option (struct gcc_options
 		sizeof "returns-nonnull-attribute" - 1 },
 	      { "object-size", SANITIZE_OBJECT_SIZE,
 		sizeof "object-size" - 1 },
+	      { "vptr", SANITIZE_VPTR, sizeof "vptr" - 1 },
 	      { NULL, 0, 0 }
 	    };
 	    const char *comma;
--- gcc/ubsan.h.jj	2014-10-25 20:46:06.460427425 +0200
+++ gcc/ubsan.h	2014-10-27 12:09:47.738576202 +0100
@@ -28,7 +28,11 @@ enum ubsan_null_ckind {
   UBSAN_REF_BINDING,
   UBSAN_MEMBER_ACCESS,
   UBSAN_MEMBER_CALL,
-  UBSAN_CTOR_CALL
+  UBSAN_CTOR_CALL,
+  UBSAN_DOWNCAST_POINTER,
+  UBSAN_DOWNCAST_REFERENCE,
+  UBSAN_UPCAST,
+  UBSAN_CAST_TO_VBASE
 };
 
 /* This controls how ubsan prints types.  Used in ubsan_type_descriptor.  */
--- gcc/sanitizer.def.jj	2014-10-25 20:46:06.374429010 +0200
+++ gcc/sanitizer.def	2014-10-27 13:54:41.087270591 +0100
@@ -433,3 +433,11 @@ DEF_SANITIZER_BUILTIN(BUILT_IN_UBSAN_HAN
 		      "__ubsan_handle_nonnull_return_abort",
 		      BT_FN_VOID_PTR,
 		      ATTR_COLD_NORETURN_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN(BUILT_IN_UBSAN_HANDLE_DYNAMIC_TYPE_CACHE_MISS,
+		      "__ubsan_handle_dynamic_type_cache_miss",
+		      BT_FN_VOID_PTR_PTR_PTR,
+		      ATTR_COLD_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN(BUILT_IN_UBSAN_HANDLE_DYNAMIC_TYPE_CACHE_MISS_ABORT,
+		      "__ubsan_handle_dynamic_type_cache_miss_abort",
+		      BT_FN_VOID_PTR_PTR_PTR,
+		      ATTR_COLD_NOTHROW_LEAF_LIST)
--- gcc/cp/cp-tree.h.jj	2014-10-25 20:46:05.433446353 +0200
+++ gcc/cp/cp-tree.h	2014-10-27 12:41:59.263503080 +0100
@@ -6333,6 +6333,13 @@ extern vec<tree> cx_error_context
 /* In c-family/cilk.c */
 extern bool cilk_valid_spawn                    (tree);
 
+/* In cp-ubsan.c */
+extern void cp_ubsan_maybe_instrument_member_call (tree);
+extern void cp_ubsan_maybe_instrument_member_access (tree);
+extern tree cp_ubsan_maybe_instrument_downcast	(location_t, tree, tree);
+extern tree cp_ubsan_maybe_instrument_cast_to_vbase (location_t, tree, tree);
+extern void cp_ubsan_fixup_downcast_instrumentation (tree *);
+
 /* -- end of C++ */
 
 #endif /* ! GCC_CP_TREE_H */
--- gcc/cp/cp-gimplify.c.jj	2014-10-25 20:46:05.484445413 +0200
+++ gcc/cp/cp-gimplify.c	2014-10-27 23:35:31.809141262 +0100
@@ -1193,9 +1193,11 @@ cp_genericize_r (tree *stmt_p, int *walk
 	*stmt_p = size_one_node;
       return NULL;
     }    
-  else if (flag_sanitize & (SANITIZE_NULL | SANITIZE_ALIGNMENT))
+  else if (flag_sanitize
+	   & (SANITIZE_NULL | SANITIZE_ALIGNMENT | SANITIZE_VPTR))
     {
-      if (TREE_CODE (stmt) == NOP_EXPR
+      if ((flag_sanitize & (SANITIZE_NULL | SANITIZE_ALIGNMENT))
+	  && TREE_CODE (stmt) == NOP_EXPR
 	  && TREE_CODE (TREE_TYPE (stmt)) == REFERENCE_TYPE)
 	ubsan_maybe_instrument_reference (stmt);
       else if (TREE_CODE (stmt) == CALL_EXPR)
@@ -1210,7 +1212,26 @@ cp_genericize_r (tree *stmt_p, int *walk
 		= 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);
+	      if (flag_sanitize & (SANITIZE_NULL | SANITIZE_ALIGNMENT))
+		ubsan_maybe_instrument_member_call (stmt, is_ctor);
+	      if ((flag_sanitize & SANITIZE_VPTR) && !is_ctor)
+		cp_ubsan_maybe_instrument_member_call (stmt);
+	    }
+	  else if (flag_sanitize & SANITIZE_VPTR)
+	    {
+	      tree fndecl = get_callee_fndecl (stmt);
+	      if (fndecl
+		  && DECL_BUILT_IN (fndecl)
+		  && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL)
+		switch (DECL_FUNCTION_CODE (fndecl))
+		  {
+		  case BUILT_IN_UBSAN_HANDLE_DYNAMIC_TYPE_CACHE_MISS:
+		  case BUILT_IN_UBSAN_HANDLE_DYNAMIC_TYPE_CACHE_MISS_ABORT:
+		    cp_ubsan_fixup_downcast_instrumentation (stmt_p);
+		    break;
+		  default:
+		    break;
+		  }
 	    }
 	}
     }
@@ -1220,6 +1241,72 @@ cp_genericize_r (tree *stmt_p, int *walk
   return NULL;
 }
 
+/* Data passed to cp_ubsan_check_member_access_r.  */
+
+struct cp_ubsan_check_member_access_data
+{
+  hash_set<tree> *pset;
+  bool is_addr;
+};
+
+/* Attempt to instrument member accesses inside of the function.  */
+
+static tree
+cp_ubsan_check_member_access_r (tree *stmt_p, int *walk_subtrees, void *data)
+{
+  tree stmt = *stmt_p, t;
+  struct cp_ubsan_check_member_access_data *ucmd
+    = (struct cp_ubsan_check_member_access_data *) data;
+  switch (TREE_CODE (stmt))
+    {
+    case ADDR_EXPR:
+      t = TREE_OPERAND (stmt, 0);
+      while ((TREE_CODE (t) == MEM_REF || TREE_CODE (t) == INDIRECT_REF)
+	     && TREE_CODE (TREE_OPERAND (t, 0)) == ADDR_EXPR)
+	t = TREE_OPERAND (TREE_OPERAND (t, 0), 0);
+      if (handled_component_p (t))
+	{
+	  *walk_subtrees = 0;
+	  ucmd->is_addr = true;
+	  cp_walk_tree (&t, cp_ubsan_check_member_access_r,
+			data, ucmd->pset);
+	  ucmd->is_addr = false;
+	}
+      break;
+    case MEM_REF:
+    case INDIRECT_REF:
+      t = TREE_OPERAND (stmt, 0);
+      if (TREE_CODE (t) == ADDR_EXPR)
+	{
+	  *walk_subtrees = 0;
+	  t = TREE_OPERAND (stmt, 0);
+	  cp_walk_tree (&t, cp_ubsan_check_member_access_r, data, ucmd->pset);
+	}
+      break;
+    case COMPONENT_REF:
+      if (!ucmd->is_addr)
+	cp_ubsan_maybe_instrument_member_access (stmt);
+      /* FALLTHRU */
+    default:
+      if (ucmd->is_addr && handled_component_p (stmt))
+	{
+	  int i, len = TREE_OPERAND_LENGTH (stmt);
+	  *walk_subtrees = 0;
+	  if (!handled_component_p (TREE_OPERAND (stmt, 0)))
+	    ucmd->is_addr = false;
+	  for (i = 0; i < len; i++)
+	    {
+	      cp_walk_tree (&TREE_OPERAND (stmt, i),
+			    cp_ubsan_check_member_access_r, data, ucmd->pset);
+	      ucmd->is_addr = false;
+	    }
+	  ucmd->is_addr = true;
+	}
+      break;
+    }
+  return NULL_TREE;
+}
+
 /* Lower C++ front end trees to GENERIC in T_P.  */
 
 static void
@@ -1233,6 +1320,14 @@ cp_genericize_tree (tree* t_p)
   cp_walk_tree (t_p, cp_genericize_r, &wtd, NULL);
   delete wtd.p_set;
   wtd.bind_expr_stack.release ();
+  if (flag_sanitize & SANITIZE_VPTR)
+    {
+      hash_set<tree> pset;
+      struct cp_ubsan_check_member_access_data ucmd;
+      ucmd.pset = &pset;
+      ucmd.is_addr = false;
+      cp_walk_tree (t_p, cp_ubsan_check_member_access_r, &ucmd, &pset);
+    }
 }
 
 /* If a function that should end with a return in non-void
--- gcc/cp/class.c.jj	2014-10-13 10:09:24.000000000 +0200
+++ gcc/cp/class.c	2014-10-27 12:55:55.238445804 +0100
@@ -430,10 +430,20 @@ build_base_path (enum tree_code code,
 	  v_offset = cp_build_indirect_ref (v_offset, RO_NULL, complain);
 	}
       else
-	v_offset = build_vfield_ref (cp_build_indirect_ref (expr, RO_NULL,
-                                                            complain),
-				     TREE_TYPE (TREE_TYPE (expr)));
-      
+	{
+	  tree t = expr;
+	  if ((flag_sanitize & SANITIZE_VPTR) && fixed_type_p == 0)
+	    {
+	      t = cp_ubsan_maybe_instrument_cast_to_vbase (input_location,
+							   probe, expr);
+	      if (t == NULL_TREE)
+		t = expr;
+	    }
+	  v_offset = build_vfield_ref (cp_build_indirect_ref (t, RO_NULL,
+							      complain),
+	  TREE_TYPE (TREE_TYPE (expr)));
+	}
+
       if (v_offset == error_mark_node)
 	return error_mark_node;
 
--- gcc/cp/constexpr.c.jj	2014-10-25 20:46:05.473445616 +0200
+++ gcc/cp/constexpr.c	2014-10-27 10:48:06.860097006 +0100
@@ -1137,8 +1137,20 @@ cxx_eval_call_expression (const constexp
   if (DECL_CLONED_FUNCTION_P (fun))
     fun = DECL_CLONED_FUNCTION (fun);
   if (is_builtin_fn (fun))
-    return cxx_eval_builtin_function_call (old_call, t, allow_non_constant,
-					   addr, non_constant_p, overflow_p);
+    {
+      /* Ignore -fsanitize=vptr instrumentation.  */
+      if ((flag_sanitize & SANITIZE_VPTR)
+	  && DECL_BUILT_IN_CLASS (fun) == BUILT_IN_NORMAL
+	  && (DECL_FUNCTION_CODE (fun)
+	      == ((flag_sanitize_recover & SANITIZE_VPTR)
+		  ? BUILT_IN_UBSAN_HANDLE_DYNAMIC_TYPE_CACHE_MISS
+		  : BUILT_IN_UBSAN_HANDLE_DYNAMIC_TYPE_CACHE_MISS_ABORT))
+	  && call_expr_nargs (t) == 4)
+	return void_node;
+
+      return cxx_eval_builtin_function_call (old_call, t, allow_non_constant,
+					     addr, non_constant_p, overflow_p);
+    }
   if (!DECL_DECLARED_CONSTEXPR_P (fun))
     {
       if (!allow_non_constant)
--- gcc/cp/Make-lang.in.jj	2014-10-25 20:46:05.467445726 +0200
+++ gcc/cp/Make-lang.in	2014-10-27 10:48:06.860097006 +0100
@@ -78,7 +78,7 @@ CXX_AND_OBJCXX_OBJS = cp/call.o cp/decl.
  cp/mangle.o cp/cp-objcp-common.o cp/name-lookup.o cp/cxx-pretty-print.o \
  cp/cp-cilkplus.o \
  cp/cp-gimplify.o cp/cp-array-notation.o cp/lambda.o \
- cp/vtable-class-hierarchy.o cp/constexpr.o $(CXX_C_OBJS)
+ cp/vtable-class-hierarchy.o cp/constexpr.o cp/cp-ubsan.o $(CXX_C_OBJS)
 
 # Language-specific object files for C++.
 CXX_OBJS = cp/cp-lang.o c-family/stub-objc.o $(CXX_AND_OBJCXX_OBJS)
--- gcc/cp/cp-ubsan.c.jj	2014-10-27 10:48:06.861096987 +0100
+++ gcc/cp/cp-ubsan.c	2014-10-27 14:15:58.599404060 +0100
@@ -0,0 +1,294 @@
+/* UndefinedBehaviorSanitizer, undefined behavior detector.
+   Copyright (C) 2014 Free Software Foundation, Inc.
+   Contributed by Jakub Jelinek <jakub@redhat.com>
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tree.h"
+#include "alloc-pool.h"
+#include "cgraph.h"
+#include "output.h"
+#include "toplev.h"
+#include "ubsan.h"
+#include "cp-tree.h"
+#include "c-family/c-common.h"
+#include "c-family/c-ubsan.h"
+#include "asan.h"
+#include "internal-fn.h"
+#include "stor-layout.h"
+#include "builtins.h"
+#include "fold-const.h"
+#include "stringpool.h"
+
+/* Cached __ubsan_vptr_type_cache decl.  */
+static GTY(()) tree ubsan_vptr_type_cache_decl;
+
+/* Emit if (__ubsan_vptr_type_cache[hash & 127] != hash) or
+   if (op && __ubsan_vptr_type_cache[hash & 127] != hash) test around
+   call.  */
+
+static tree
+cp_ubsan_cache_test (location_t loc, tree op, tree hash, tree call,
+		     enum ubsan_null_ckind ckind)
+{
+  tree t = fold_build2_loc (loc, BIT_AND_EXPR, pointer_sized_int_node, hash,
+			    build_int_cst (pointer_sized_int_node, 127));
+  t = build4_loc (loc, ARRAY_REF, pointer_sized_int_node,
+		     ubsan_vptr_type_cache_decl, t, NULL_TREE, NULL_TREE);
+  tree cond = fold_build2_loc (loc, NE_EXPR, boolean_type_node, t, hash);
+  if (ckind == UBSAN_DOWNCAST_POINTER)
+    cond = fold_build2_loc (loc, TRUTH_ANDIF_EXPR, boolean_type_node,
+			    fold_build2_loc (loc, NE_EXPR, boolean_type_node,
+					     op,
+					     build_zero_cst (TREE_TYPE (op))),
+			    cond);
+  return fold_build3_loc (loc, COND_EXPR, void_type_node, cond, call,
+			  void_node);
+}
+
+/* Helper function for
+   cp_ubsan_maybe_instrument_{member_{call,access},downcast}.  */
+
+static tree
+cp_ubsan_maybe_instrument_vptr (location_t loc, tree op, tree type,
+				bool is_addr, enum ubsan_null_ckind ckind)
+{
+  if (!flag_rtti || flag_sanitize_undefined_trap_on_error)
+    return NULL_TREE;
+
+  if (current_function_decl
+      && lookup_attribute ("no_sanitize_undefined",
+			   DECL_ATTRIBUTES (current_function_decl)))
+    return NULL_TREE;
+
+  type = TYPE_MAIN_VARIANT (type);
+  if (!CLASS_TYPE_P (type) || !CLASSTYPE_VTABLES (type))
+    return NULL_TREE;
+
+  /* T t; t.foo (); doesn't need instrumentation, if the type is known.  */
+  if (is_addr
+      && TREE_CODE (op) == ADDR_EXPR
+      && DECL_P (TREE_OPERAND (op, 0))
+      && same_type_p (type,
+		      TYPE_MAIN_VARIANT (TREE_TYPE (TREE_OPERAND (op, 0)))))
+    return NULL_TREE;
+
+  const char *mangled = mangle_type_string (type);
+  hashval_t str_hash1 = htab_hash_string (mangled);
+  hashval_t str_hash2 = iterative_hash (mangled, strlen (mangled), 0);
+  tree str_hash = wide_int_to_tree (uint64_type_node,
+				    wi::uhwi (((uint64_t) str_hash1 << 32)
+					      | str_hash2, 64));
+  if (!is_addr)
+    op = build_fold_addr_expr_loc (loc, op);
+  op = save_expr (op);
+  tree vptr = fold_build3_loc (loc, COMPONENT_REF,
+			       TREE_TYPE (TYPE_VFIELD (type)),
+			       build_fold_indirect_ref_loc (loc, op),
+			       TYPE_VFIELD (type), NULL_TREE);
+  vptr = fold_convert_loc (loc, pointer_sized_int_node, vptr);
+  vptr = fold_convert_loc (loc, uint64_type_node, vptr);
+  vptr = build1_loc (loc, SAVE_EXPR, uint64_type_node, vptr);
+  /* Hash in 2 different hashes of mangled type name with the value of
+     vptr pointer.  */
+  tree cst = wide_int_to_tree (uint64_type_node,
+			       wi::uhwi (((uint64_t) 0x9ddfea08 << 32)
+					 | 0xeb382d69, 64));
+  tree t1 = fold_build2_loc (loc, BIT_XOR_EXPR, uint64_type_node, 
+			     str_hash, vptr);
+  t1 = fold_build2_loc (loc, MULT_EXPR, uint64_type_node, t1, cst);
+  t1 = build1_loc (loc, SAVE_EXPR, uint64_type_node, t1);
+  tree t2 = fold_build2_loc (loc, LSHIFT_EXPR, uint64_type_node,
+			     t1, build_int_cst (integer_type_node, 47));
+  t2 = fold_build2_loc (loc, BIT_XOR_EXPR, uint64_type_node, t2, t1);
+  t2 = fold_build2_loc (loc, BIT_XOR_EXPR, uint64_type_node, vptr, t2);
+  t2 = fold_build2_loc (loc, MULT_EXPR, uint64_type_node, t2, cst);
+  t2 = build1_loc (loc, SAVE_EXPR, uint64_type_node, t2);
+  tree t3 = fold_build2_loc (loc, LSHIFT_EXPR, uint64_type_node,
+			     t2, build_int_cst (integer_type_node, 47));
+  t3 = fold_build2_loc (loc, BIT_XOR_EXPR, uint64_type_node, t3, t2);
+  t3 = fold_build2_loc (loc, MULT_EXPR, uint64_type_node, t3, cst);
+  tree hash = fold_convert_loc (loc, pointer_sized_int_node, t3);
+  hash = build1_loc (loc, SAVE_EXPR, pointer_sized_int_node, hash);
+  if (ubsan_vptr_type_cache_decl == NULL_TREE)
+    {
+      tree atype = build_array_type_nelts (pointer_sized_int_node, 128);
+      tree array = build_decl (UNKNOWN_LOCATION, VAR_DECL,
+			       get_identifier ("__ubsan_vptr_type_cache"),
+			       atype);
+      DECL_ARTIFICIAL (array) = 1;
+      DECL_IGNORED_P (array) = 1;
+      TREE_PUBLIC (array) = 1;
+      TREE_STATIC (array) = 1;
+      DECL_EXTERNAL (array) = 1;
+      DECL_VISIBILITY (array) = VISIBILITY_DEFAULT;
+      DECL_VISIBILITY_SPECIFIED (array) = 1;
+      layout_decl (array, 0);
+      ubsan_vptr_type_cache_decl = array;
+    }
+  tree ti_decl = get_tinfo_decl (type);
+  mark_used (ti_decl);
+  tree data
+    = ubsan_create_data ("__ubsan_vptr_data", 1, &loc,
+			 ubsan_type_descriptor (type), NULL_TREE,
+			 build_address (ti_decl),
+			 build_int_cst (unsigned_char_type_node, ckind),
+			 NULL_TREE);
+  data = build_fold_addr_expr_loc (loc, data);
+  enum built_in_function bcode
+    = (flag_sanitize_recover & SANITIZE_VPTR)
+      ? BUILT_IN_UBSAN_HANDLE_DYNAMIC_TYPE_CACHE_MISS
+      : BUILT_IN_UBSAN_HANDLE_DYNAMIC_TYPE_CACHE_MISS_ABORT;
+  tree call = builtin_decl_explicit (bcode), ret;
+  /* As UBSAN_DOWNCAST_* is called from build_static_cast_1, and
+     UBSAN_CAST_TO_VBASE during build_base_path, emit there
+     only the call and add the guard when genericizing the call.  */
+  switch (ckind)
+    {
+    default:
+      call = build_call_expr_loc (loc, call, 3, data, op,
+				  ubsan_encode_value (hash));
+      TREE_SIDE_EFFECTS (call) = 1;
+      ret = cp_ubsan_cache_test (loc, op, hash, call, ckind);
+      break;
+    case UBSAN_DOWNCAST_POINTER:
+    case UBSAN_DOWNCAST_REFERENCE:
+    case UBSAN_CAST_TO_VBASE:
+      call = build_call_expr_loc (loc, call, 4, data, op,
+				  ubsan_encode_value (hash),
+				  build_int_cst (integer_type_node, ckind));
+      TREE_SIDE_EFFECTS (call) = 1;
+      ret = call;
+      break;
+    }
+  return fold_build2 (COMPOUND_EXPR, TREE_TYPE (op), ret, op);
+}
+
+/* Instrument a member call (but not constructor call) if needed.  */
+
+void
+cp_ubsan_maybe_instrument_member_call (tree stmt)
+{
+  if (call_expr_nargs (stmt) == 0)
+    return;
+  tree *opp = &CALL_EXPR_ARG (stmt, 0);
+  tree op = *opp;
+  if (op == error_mark_node
+      || !POINTER_TYPE_P (TREE_TYPE (op)))
+    return;
+  while (TREE_CODE (op) == COMPOUND_EXPR)
+    {
+      opp = &TREE_OPERAND (op, 1);
+      op = *opp;
+    }
+  op = cp_ubsan_maybe_instrument_vptr (EXPR_LOCATION (stmt), op,
+				       TREE_TYPE (TREE_TYPE (op)),
+				       true, UBSAN_MEMBER_CALL);
+  if (op)
+    *opp = op;
+}
+
+/* Instrument a member access.  */
+
+void
+cp_ubsan_maybe_instrument_member_access (tree stmt)
+{
+  if (DECL_ARTIFICIAL (TREE_OPERAND (stmt, 1)))
+    return;
+
+  tree base = TREE_OPERAND (stmt, 0);
+  if (TREE_CODE (base) == COMPONENT_REF
+      && DECL_ARTIFICIAL (TREE_OPERAND (base, 1)))
+    {
+      tree base2 = TREE_OPERAND (base, 0);
+      while (TREE_CODE (base2) == COMPONENT_REF
+	     || TREE_CODE (base2) == ARRAY_REF
+	     || TREE_CODE (base2) == ARRAY_RANGE_REF)
+	base2 = TREE_OPERAND (base2, 0);
+      if (TREE_CODE (base2) != INDIRECT_REF
+	  && TREE_CODE (base2) != MEM_REF)
+	return;
+    }
+  else if (TREE_CODE (base) != INDIRECT_REF
+	   && TREE_CODE (base) != MEM_REF)
+    return;
+
+  base = cp_ubsan_maybe_instrument_vptr (EXPR_LOCATION (stmt), base,
+					 TREE_TYPE (base), false,
+					 UBSAN_MEMBER_ACCESS);
+  if (base)
+    TREE_OPERAND (stmt, 0)
+      = build_fold_indirect_ref_loc (EXPR_LOCATION (stmt), base);
+}
+
+/* Instrument downcast.  */
+
+tree
+cp_ubsan_maybe_instrument_downcast (location_t loc, tree type, tree op)
+{
+  if (!POINTER_TYPE_P (type)
+      || !POINTER_TYPE_P (TREE_TYPE (op))
+      || !CLASS_TYPE_P (TREE_TYPE (type))
+      || !CLASS_TYPE_P (TREE_TYPE (TREE_TYPE (op)))
+      || !DERIVED_FROM_P (TREE_TYPE (TREE_TYPE (op)), TREE_TYPE (type)))
+    return NULL_TREE;
+
+  return cp_ubsan_maybe_instrument_vptr (loc, op, TREE_TYPE (type), true,
+					 TREE_CODE (type) == POINTER_TYPE
+					 ? UBSAN_DOWNCAST_POINTER
+					 : UBSAN_DOWNCAST_REFERENCE);
+}
+
+/* Instrument cast to virtual base.  */
+
+tree
+cp_ubsan_maybe_instrument_cast_to_vbase (location_t loc, tree type, tree op)
+{
+  return cp_ubsan_maybe_instrument_vptr (loc, op, type, true,
+					 UBSAN_CAST_TO_VBASE);
+}
+
+/* Fix up downcast instrumentation.  */
+
+void
+cp_ubsan_fixup_downcast_instrumentation (tree *stmt_p)
+{
+  tree stmt = *stmt_p;
+  if (call_expr_nargs (stmt) != 4)
+    return;
+
+  location_t loc = EXPR_LOCATION (stmt);
+  tree data = CALL_EXPR_ARG (stmt, 0);
+  tree op = CALL_EXPR_ARG (stmt, 1);
+  tree hash = CALL_EXPR_ARG (stmt, 2);
+  enum ubsan_null_ckind ckind
+    = (enum ubsan_null_ckind) tree_to_shwi (CALL_EXPR_ARG (stmt, 3));
+  enum built_in_function bcode
+    = (flag_sanitize_recover & SANITIZE_VPTR)
+      ? BUILT_IN_UBSAN_HANDLE_DYNAMIC_TYPE_CACHE_MISS
+      : BUILT_IN_UBSAN_HANDLE_DYNAMIC_TYPE_CACHE_MISS_ABORT;
+  tree call = builtin_decl_explicit (bcode);
+  call = build_call_expr_loc (loc, call, 3, data, op,
+			      ubsan_encode_value (hash));
+  TREE_SIDE_EFFECTS (call) = 1;
+  *stmt_p = cp_ubsan_cache_test (loc, op, hash, call, ckind);
+}
+
+#include "gt-cp-cp-ubsan.h"
--- gcc/cp/typeck.c.jj	2014-10-25 20:46:05.448446076 +0200
+++ gcc/cp/typeck.c	2014-10-27 10:48:06.863096948 +0100
@@ -2424,8 +2424,8 @@ build_class_member_access_expr (tree obj
 	  member_type = cp_build_qualified_type (member_type, type_quals);
 	}
 
-      result = build3 (COMPONENT_REF, member_type, object, member,
-		       NULL_TREE);
+      result = build3_loc (input_location, COMPONENT_REF, member_type,
+			   object, member, NULL_TREE);
       result = fold_if_not_in_template (result);
 
       /* Mark the expression const or volatile, as appropriate.  Even
@@ -6503,11 +6503,21 @@ build_static_cast_1 (tree type, tree exp
       base = lookup_base (TREE_TYPE (type), intype,
 			  c_cast_p ? ba_unique : ba_check,
 			  NULL, complain);
+      expr = build_address (expr);
+
+      if (flag_sanitize & SANITIZE_VPTR)
+	{
+	  tree ubsan_check
+	    = cp_ubsan_maybe_instrument_downcast (input_location, type, expr);
+	  if (ubsan_check)
+	    expr = ubsan_check;
+	}
 
       /* Convert from "B*" to "D*".  This function will check that "B"
 	 is not a virtual base of "D".  */
-      expr = build_base_path (MINUS_EXPR, build_address (expr),
-			      base, /*nonnull=*/false, complain);
+      expr = build_base_path (MINUS_EXPR, expr, base, /*nonnull=*/false,
+			      complain);
+
       /* Convert the pointer to a reference -- but then remember that
 	 there are no expressions with reference type in C++.
 
@@ -6635,7 +6645,16 @@ build_static_cast_1 (tree type, tree exp
 			  NULL, complain);
       expr = build_base_path (MINUS_EXPR, expr, base, /*nonnull=*/false,
 			      complain);
-      return cp_fold_convert(type, expr);
+
+      if (flag_sanitize & SANITIZE_VPTR)
+	{
+	  tree ubsan_check
+	    = cp_ubsan_maybe_instrument_downcast (input_location, type, expr);
+	  if (ubsan_check)
+	    expr = ubsan_check;
+	}
+
+      return cp_fold_convert (type, expr);
     }
 
   if ((TYPE_PTRDATAMEM_P (type) && TYPE_PTRDATAMEM_P (intype))
--- gcc/cp/config-lang.in.jj	2014-10-25 20:46:05.485445394 +0200
+++ gcc/cp/config-lang.in	2014-10-27 10:48:06.863096948 +0100
@@ -29,4 +29,4 @@ compilers="cc1plus\$(exeext)"
 
 target_libs="target-libstdc++-v3"
 
-gtfiles="\$(srcdir)/cp/rtti.c \$(srcdir)/cp/mangle.c \$(srcdir)/cp/name-lookup.h \$(srcdir)/cp/name-lookup.c \$(srcdir)/cp/cp-tree.h \$(srcdir)/cp/decl.h \$(srcdir)/cp/call.c \$(srcdir)/cp/decl.c \$(srcdir)/cp/decl2.c \$(srcdir)/cp/pt.c \$(srcdir)/cp/repo.c \$(srcdir)/cp/semantics.c \$(srcdir)/cp/tree.c \$(srcdir)/cp/parser.h \$(srcdir)/cp/parser.c \$(srcdir)/cp/method.c \$(srcdir)/cp/typeck2.c \$(srcdir)/c-family/c-common.c \$(srcdir)/c-family/c-common.h \$(srcdir)/c-family/c-objc.h \$(srcdir)/c-family/c-lex.c \$(srcdir)/c-family/c-pragma.h \$(srcdir)/c-family/c-pragma.c \$(srcdir)/cp/class.c \$(srcdir)/cp/cp-objcp-common.c \$(srcdir)/cp/cp-lang.c \$(srcdir)/cp/except.c \$(srcdir)/cp/vtable-class-hierarchy.c \$(srcdir)/cp/constexpr.c"
+gtfiles="\$(srcdir)/cp/rtti.c \$(srcdir)/cp/mangle.c \$(srcdir)/cp/name-lookup.h \$(srcdir)/cp/name-lookup.c \$(srcdir)/cp/cp-tree.h \$(srcdir)/cp/decl.h \$(srcdir)/cp/call.c \$(srcdir)/cp/decl.c \$(srcdir)/cp/decl2.c \$(srcdir)/cp/pt.c \$(srcdir)/cp/repo.c \$(srcdir)/cp/semantics.c \$(srcdir)/cp/tree.c \$(srcdir)/cp/parser.h \$(srcdir)/cp/parser.c \$(srcdir)/cp/method.c \$(srcdir)/cp/typeck2.c \$(srcdir)/c-family/c-common.c \$(srcdir)/c-family/c-common.h \$(srcdir)/c-family/c-objc.h \$(srcdir)/c-family/c-lex.c \$(srcdir)/c-family/c-pragma.h \$(srcdir)/c-family/c-pragma.c \$(srcdir)/cp/class.c \$(srcdir)/cp/cp-objcp-common.c \$(srcdir)/cp/cp-lang.c \$(srcdir)/cp/except.c \$(srcdir)/cp/vtable-class-hierarchy.c \$(srcdir)/cp/constexpr.c \$(srcdir)/cp/cp-ubsan.c"
--- gcc/flag-types.h.jj	2014-10-25 20:46:05.494445228 +0200
+++ gcc/flag-types.h	2014-10-27 10:48:06.864096929 +0100
@@ -237,13 +237,14 @@ enum sanitize_code {
   SANITIZE_NONNULL_ATTRIBUTE = 1UL << 18,
   SANITIZE_RETURNS_NONNULL_ATTRIBUTE = 1UL << 19,
   SANITIZE_OBJECT_SIZE = 1UL << 20,
+  SANITIZE_VPTR = 1UL << 21,
   SANITIZE_UNDEFINED = SANITIZE_SHIFT | SANITIZE_DIVIDE | SANITIZE_UNREACHABLE
 		       | SANITIZE_VLA | SANITIZE_NULL | SANITIZE_RETURN
 		       | SANITIZE_SI_OVERFLOW | SANITIZE_BOOL | SANITIZE_ENUM
 		       | SANITIZE_BOUNDS | SANITIZE_ALIGNMENT
 		       | SANITIZE_NONNULL_ATTRIBUTE
 		       | SANITIZE_RETURNS_NONNULL_ATTRIBUTE
-		       | SANITIZE_OBJECT_SIZE,
+		       | SANITIZE_OBJECT_SIZE | SANITIZE_VPTR,
   SANITIZE_NONDEFAULT = SANITIZE_FLOAT_DIVIDE | SANITIZE_FLOAT_CAST
 };
 
--- gcc/testsuite/g++.dg/ubsan/vptr-4.C.jj	2014-10-27 10:48:06.864096929 +0100
+++ gcc/testsuite/g++.dg/ubsan/vptr-4.C	2014-10-27 10:48:06.864096929 +0100
@@ -0,0 +1,54 @@
+// Verify that -fsanitize=vptr downcast instrumentation works properly
+// inside of constexpr.
+// { dg-do compile }
+// { dg-options "-std=c++11 -fsanitize=vptr" }
+
+struct S {
+  constexpr S() : a(0) {}
+  int a;
+  int f() { return 0; }
+  virtual int v() { return 0; }
+};
+
+struct T : S {
+  constexpr T() : b(0) {}
+  int b;
+  int g() { return 0; }
+  virtual int v() { return 1; }
+  constexpr const T *foo() { return (const T *) reinterpret_cast<const S *> (this); }
+};
+
+constexpr T t;
+constexpr const T *p = t.foo ();
+
+template <typename U>
+struct V {
+  constexpr V() : a(0) {}
+  int a;
+  int f() { return 0; }
+  virtual int v() { return 0; }
+};
+
+template <typename U>
+struct W : V<U> {
+  constexpr W() : b(0) {}
+  int b;
+  int g() { return 0; }
+  virtual int v() { return 1; }
+  constexpr const W<U> *foo() { return (const W<U> *) reinterpret_cast<const V<U> *> (this); }
+};
+
+constexpr W<int> w;
+constexpr const W<int> *s = w.foo ();
+
+template <typename U>
+int foo (void)
+{
+  static constexpr T t;
+  static constexpr const T *p = t.foo ();
+  static constexpr W<U> w;
+  static constexpr const W<U> *s = w.foo ();
+  return t.b + w.b;
+}
+
+int x = foo <char> ();
--- gcc/testsuite/g++.dg/ubsan/vptr-5.C.jj	2014-10-27 10:48:06.864096929 +0100
+++ gcc/testsuite/g++.dg/ubsan/vptr-5.C	2014-10-27 10:48:06.864096929 +0100
@@ -0,0 +1,32 @@
+// { dg-do run }
+// { dg-options "-fsanitize=vptr" }
+
+struct S
+{
+  S() : a(0) {}
+  ~S() {}
+  int a;
+  int f() { return 0; }
+  virtual int v() { return 0; }
+};
+
+struct T : S
+{
+  T() : b(0) {}
+  int b;
+  int g() { return 0; }
+  virtual int v() { return 1; }
+};
+
+T *
+foo (S *p)
+{
+  return (T *) p;
+}
+
+int
+main ()
+{
+  if (foo (__null) != __null)
+    __builtin_abort ();
+}
--- gcc/testsuite/g++.dg/ubsan/vptr-8.C.jj	2014-10-27 13:05:18.638094867 +0100
+++ gcc/testsuite/g++.dg/ubsan/vptr-8.C	2014-10-27 16:26:58.213905581 +0100
@@ -0,0 +1,32 @@
+// { dg-do run }
+// { dg-shouldfail "ubsan" }
+// { dg-options "-fsanitize=vptr -fno-sanitize-recover=vptr" }
+
+extern "C" void abort ();
+
+struct S { virtual void f () {} };
+struct T : S { ~T (); };
+struct U : S { };
+struct V : T, virtual U {};
+
+U *up;
+V *vp;
+
+int
+main ()
+{
+  V v;
+  up = vp = &v;
+}
+
+T::~T ()
+{
+  if (vp != up)
+   abort ();
+}
+
+// { dg-output "\[^\n\r]*vptr-8.C:24:\[0-9]*: runtime error: cast to virtual base of address 0x\[0-9a-fA-F]* which does not point to an object of type 'V'(\n|\r\n|\r)" }
+// { dg-output "0x\[0-9a-fA-F]*: note: object is of type 'T'(\n|\r\n|\r)" }
+// { dg-output "  ?.. .. .. ..  ?.. .. .. ..  ?.. .. .. .. \[^\n\r]*(\n|\r\n|\r)" }
+// { dg-output "              ?\\^~~~~~~~~~~\[^\n\r]*(\n|\r\n|\r)" }
+// { dg-output "              ?vptr for 'T'\[^\n\r]*(\n|\r\n|\r)" }
--- gcc/testsuite/g++.dg/ubsan/vptr-3.C.jj	2014-10-27 10:48:06.865096910 +0100
+++ gcc/testsuite/g++.dg/ubsan/vptr-3.C	2014-10-27 10:48:06.865096910 +0100
@@ -0,0 +1,184 @@
+// { dg-do run { target { ilp32 || lp64 } } }
+// { dg-options "-fsanitize=vptr" }
+
+struct S
+{
+  S() : a(0) {}
+  ~S() {}
+  int a;
+  int f() { return 0; }
+  virtual int v() { return 0; }
+};
+  
+struct T : S
+{
+  T() : b(0) {}
+  int b;
+  int g() { return 0; }
+  virtual int v() { return 1; }
+};
+
+struct U : S, T { virtual int v() { return 2; } }; // { dg-warning "direct base .S. inaccessible in .U. due to ambiguity" }
+struct V : S {};
+
+void
+foo ()
+{
+  T t;
+  (void)t.a;
+  (void)t.b;
+  (void)t.f();
+  (void)t.g();
+  (void)t.v();
+  (void)t.S::v();
+    
+  U u;
+  (void)u.T::a;
+  (void)u.b;
+  (void)u.T::f();
+  (void)u.g();
+  (void)u.v();
+  (void)u.T::v();
+  (void)((T&)u).S::v();
+}
+
+T *x;
+template <int N>
+__attribute__((noinline, noclone)) int
+bar (T *p, int q)
+{
+  switch (q)
+    {
+    // These shouldn't fail:
+    case 0x10:
+    case 0x20:
+    case 0x30:
+    case 0x40:
+      {
+	T &r = *p;
+	break;
+      }
+    case 0x21:
+    case 0x31:
+      return p->b;
+    case 0x22:
+    case 0x32:
+      return p->g ();
+    case 0x23:
+    case 0x33:
+      x = static_cast<T*>(reinterpret_cast<S*>(p));
+      break;
+    case 0x44:
+      return reinterpret_cast<U*>(p)->v() - 2;
+    // These should:
+    case 0x11:
+      return p->b;
+    // { dg-output "\[^\n\r]*vptr-3.C:75:\[0-9]*: runtime error: member access within address 0x\[0-9a-fA-F]* which does not point to an object of type 'T'(\n|\r\n|\r)" }
+    // { dg-output "0x\[0-9a-fA-F]*: note: object is of type 'S'(\n|\r\n|\r)" }
+    // { dg-output " .. .. .. ..  .. .. .. .. .. .. .. ..  \[^\n\r]*(\n|\r\n|\r)" }
+    // { dg-output "              \\^~~~~~~~~~~\[^\n\r]*(\n|\r\n|\r)" }
+    // { dg-output "              vptr for 'S'\[^\n\r]*(\n|\r\n|\r)" }
+    case 0x12:
+      return p->g ();
+    // { dg-output "\[^\n\r]*vptr-3.C:82:\[0-9]*: runtime error: member call on address 0x\[0-9a-fA-F]* which does not point to an object of type 'T'(\n|\r\n|\r)" }
+    // { dg-output "0x\[0-9a-fA-F]*: note: object is of type 'S'(\n|\r\n|\r)" }
+    // { dg-output " .. .. .. ..  .. .. .. .. .. .. .. ..  \[^\n\r]*(\n|\r\n|\r)" }
+    // { dg-output "              \\^~~~~~~~~~~\[^\n\r]*(\n|\r\n|\r)" }
+    // { dg-output "              vptr for 'S'\[^\n\r]*(\n|\r\n|\r)" }
+    case 0x13:
+      x = static_cast<T*>(reinterpret_cast<S*>(p));
+      break;
+    // { dg-output "\[^\n\r]*vptr-3.C:89:\[0-9]*: runtime error: downcast of address 0x\[0-9a-fA-F]* which does not point to an object of type 'T'(\n|\r\n|\r)" }
+    // { dg-output "0x\[0-9a-fA-F]*: note: object is of type 'S'(\n|\r\n|\r)" }
+    // { dg-output " .. .. .. ..  .. .. .. .. .. .. .. ..  \[^\n\r]*(\n|\r\n|\r)" }
+    // { dg-output "              \\^~~~~~~~~~~\[^\n\r]*(\n|\r\n|\r)" }
+    // { dg-output "              vptr for 'S'\[^\n\r]*(\n|\r\n|\r)" }
+    case 0x34:
+      return reinterpret_cast<U*>(p)->v() - 2;
+    // { dg-output "\[^\n\r]*vptr-3.C:97:\[0-9]*: runtime error: member call on address 0x\[0-9a-fA-F]* which does not point to an object of type 'U'(\n|\r\n|\r)" }
+    // { dg-output "0x\[0-9a-fA-F]*: note: object is base class subobject at offset 16 within object of type 'U'(\n|\r\n|\r)" { target lp64 } }
+    // { dg-output "0x\[0-9a-fA-F]*: note: object is base class subobject at offset 8 within object of type 'U'(\n|\r\n|\r)" { target ilp32 } }
+    // { dg-output " .. .. .. ..  .. .. .. .. .. .. .. ..  .. .. .. .. .. .. .. ..  .. .. .. .. .. .. .. ..  \[^\n\r]*(\n|\r\n|\r)" }
+    // { dg-output "              \\^                                                 ~~~~~~~~~~~~~~~~~~~~~~~(\n|\r\n|\r)" { target lp64 } }
+    // { dg-output "                                                                vptr for 'T' base class of 'U'\[^\n\r]*(\n|\r\n|\r)" { target lp64 } }
+    // { dg-output "              \\^                        ~~~~~~~~~~~(\n|\r\n|\r)" { target ilp32 } }
+    // { dg-output "                                       vptr for 'T' base class of 'U'\[^\n\r]*(\n|\r\n|\r)" { target ilp32 } }
+    case 0x41:
+      return p->b;
+    // { dg-output "\[^\n\r]*vptr-3.C:107:\[0-9]*: runtime error: member access within address 0x\[0-9a-fA-F]* which does not point to an object of type 'T'(\n|\r\n|\r)" }
+    // { dg-output "0x\[0-9a-fA-F]*: note: object is of type 'U'(\n|\r\n|\r)" }
+    // { dg-output " .. .. .. ..  .. .. .. .. .. .. .. ..  \[^\n\r]*(\n|\r\n|\r)" }
+    // { dg-output "              \\^~~~~~~~~~~\[^\n\r]*(\n|\r\n|\r)" }
+    // { dg-output "              vptr for 'U'\[^\n\r]*(\n|\r\n|\r)" }
+    case 0x42:
+      return p->g ();
+    // { dg-output "\[^\n\r]*vptr-3.C:114:\[0-9]*: runtime error: member call on address 0x\[0-9a-fA-F]* which does not point to an object of type 'T'(\n|\r\n|\r)" }
+    // { dg-output "0x\[0-9a-fA-F]*: note: object is of type 'U'(\n|\r\n|\r)" }
+    // { dg-output " .. .. .. ..  .. .. .. .. .. .. .. ..  \[^\n\r]*(\n|\r\n|\r)" }
+    // { dg-output "              \\^~~~~~~~~~~\[^\n\r]*(\n|\r\n|\r)" }
+    // { dg-output "              vptr for 'U'\[^\n\r]*(\n|\r\n|\r)" }
+    case 0x43:
+      x = static_cast<T*>(reinterpret_cast<S*>(p));
+      break;
+    // { dg-output "\[^\n\r]*vptr-3.C:121:\[0-9]*: runtime error: downcast of address 0x\[0-9a-fA-F]* which does not point to an object of type 'T'(\n|\r\n|\r)" }
+    // { dg-output "0x\[0-9a-fA-F]*: note: object is of type 'U'(\n|\r\n|\r)" }
+    // { dg-output " .. .. .. ..  .. .. .. .. .. .. .. ..  \[^\n\r]*(\n|\r\n|\r)" }
+    // { dg-output "              \\^~~~~~~~~~~\[^\n\r]*(\n|\r\n|\r)" }
+    // { dg-output "              vptr for 'U'\[^\n\r]*(\n|\r\n|\r)" }
+    case 0x51:
+      return p->b;
+    // { dg-output "\[^\n\r]*vptr-3.C:129:\[0-9]*: runtime error: member access within address 0x\[0-9a-fA-F]* which does not point to an object of type 'T'(\n|\r\n|\r)" }
+    // { dg-output "0x\[0-9a-fA-F]*: note: object has invalid vptr(\n|\r\n|\r)" }
+    // { dg-output " .. .. .. ..  00 00 00 00 00 00 00 00  \[^\n\r]*(\n|\r\n|\r)" { target lp64 } }
+    // { dg-output "              \\^~~~~~~~~~~~~~~~~~~~~~~\[^\n\r]*(\n|\r\n|\r)" { target lp64 } }
+    // { dg-output "  ?.. .. .. ..  ?00 00 00 00  ?.. .. .. ..  ?\[^\n\r]*(\n|\r\n|\r)" { target ilp32 } }
+    // { dg-output "              \\^~~~~~~~~~~\[^\n\r]*(\n|\r\n|\r)" { target ilp32 } }
+    // { dg-output "              invalid vptr" }
+    }
+  return 0;
+}
+
+char b[sizeof (U)] __attribute__((aligned (__alignof__ (U)))) = {};
+
+__attribute__((noinline, noclone)) void
+baz (int q)
+{
+  T *p = 0;
+  S *s = 0;
+  U *u = 0;
+  switch (q)
+    {
+    case 0x10: case 0x11: case 0x12: case 0x13:
+      s = new S;
+      bar<0> (reinterpret_cast<T *>(s), q);
+      delete s;
+      break;
+    case 0x20: case 0x21: case 0x22: case 0x23:
+      p = new T;
+      bar<0> (p, q);
+      delete p;
+      break;
+    case 0x30: case 0x31: case 0x32: case 0x33: case 0x34:
+      u = new U;
+      bar<0> (u, q);
+      delete u;
+      break;
+    case 0x40: case 0x41: case 0x42: case 0x43: case 0x44:
+      u = new U;
+      bar<0> (reinterpret_cast<T *>(u), q);
+      delete u;
+      break;
+    case 0x51:
+      p = reinterpret_cast<T*>(b);
+      bar<0> (p, q);
+      break;
+    }
+}
+
+int
+main ()
+{
+  foo ();
+  for (int q = 0; q < 0x52; q++)
+    baz (q);
+}
--- gcc/testsuite/g++.dg/ubsan/vptr-7.C.jj	2014-10-27 10:48:06.865096910 +0100
+++ gcc/testsuite/g++.dg/ubsan/vptr-7.C	2014-10-27 21:40:40.950984610 +0100
@@ -0,0 +1,26 @@
+// { dg-do compile }
+// { dg-skip-if "" { *-*-* } { "-flto" } { "" } }
+// { dg-options "-fsanitize=vptr -O2 -fdump-tree-optimized" }
+
+struct S { virtual ~S (); int i; };
+
+int *
+f1 (S *p)
+{
+  return &p->i;
+}
+
+int *
+f2 (S *p)
+{
+  return &*&p->i;
+}
+
+int &
+f3 (S *p)
+{
+  return p->i;
+}
+
+// { dg-final { scan-tree-dump-times "__ubsan_handle_dynamic_type_cache_miss" 0 "optimized" } }
+// { dg-final { cleanup-tree-dump "optimized" } }
--- gcc/testsuite/g++.dg/ubsan/vptr-9.C.jj	2014-10-27 13:40:24.441196253 +0100
+++ gcc/testsuite/g++.dg/ubsan/vptr-9.C	2014-10-27 16:26:13.384728254 +0100
@@ -0,0 +1,22 @@
+// { dg-do run }
+// { dg-shouldfail "ubsan" }
+// { dg-options "-fsanitize=vptr -fno-sanitize-recover=undefined" }
+
+struct S { virtual int f () { return 0; } };
+struct T : virtual S {};
+struct U { virtual int f () { return 0; } };
+
+int
+main ()
+{
+  U u;
+  T *t = (T *) &u;
+  S *s = t;
+  return s->f ();
+}
+
+// { dg-output "\[^\n\r]*vptr-9.C:14:\[0-9]*: runtime error: cast to virtual base of address 0x\[0-9a-fA-F]* which does not point to an object of type 'T'(\n|\r\n|\r)" }
+// { dg-output "0x\[0-9a-fA-F]*: note: object is of type 'U'(\n|\r\n|\r)" }
+// { dg-output "  ?.. .. .. ..  ?.. .. .. ..  ?.. .. .. .. \[^\n\r]*(\n|\r\n|\r)" }
+// { dg-output "              ?\\^~~~~~~~~~~\[^\n\r]*(\n|\r\n|\r)" }
+// { dg-output "              ?vptr for 'U'\[^\n\r]*(\n|\r\n|\r)" }
--- gcc/testsuite/g++.dg/ubsan/vptr-2.C.jj	2014-10-27 10:48:06.865096910 +0100
+++ gcc/testsuite/g++.dg/ubsan/vptr-2.C	2014-10-27 10:48:06.865096910 +0100
@@ -0,0 +1,184 @@
+// { dg-do run { target { ilp32 || lp64 } } }
+// { dg-options "-fsanitize=vptr" }
+
+struct S
+{
+  S() : a(0) {}
+  ~S() {}
+  int a;
+  int f() { return 0; }
+  virtual int v() { return 0; }
+};
+  
+struct T : S
+{
+  T() : b(0) {}
+  int b;
+  int g() { return 0; }
+  virtual int v() { return 1; }
+};
+
+struct U : S, T { virtual int v() { return 2; } }; // { dg-warning "direct base .S. inaccessible in .U. due to ambiguity" }
+struct V : S {};
+
+void
+foo ()
+{
+  T t;
+  (void)t.a;
+  (void)t.b;
+  (void)t.f();
+  (void)t.g();
+  (void)t.v();
+  (void)t.S::v();
+    
+  U u;
+  (void)u.T::a;
+  (void)u.b;
+  (void)u.T::f();
+  (void)u.g();
+  (void)u.v();
+  (void)u.T::v();
+  (void)((T&)u).S::v();
+}
+
+T *x;
+template <typename S, typename T, typename U>
+__attribute__((noinline, noclone)) int
+bar (T *p, int q)
+{
+  switch (q)
+    {
+    // These shouldn't fail:
+    case 0x10:
+    case 0x20:
+    case 0x30:
+    case 0x40:
+      {
+	T &r = *p;
+	break;
+      }
+    case 0x21:
+    case 0x31:
+      return p->b;
+    case 0x22:
+    case 0x32:
+      return p->g ();
+    case 0x23:
+    case 0x33:
+      x = static_cast<T*>(reinterpret_cast<S*>(p));
+      break;
+    case 0x44:
+      return reinterpret_cast<U*>(p)->v() - 2;
+    // These should:
+    case 0x11:
+      return p->b;
+    // { dg-output "\[^\n\r]*vptr-2.C:75:\[0-9]*: runtime error: member access within address 0x\[0-9a-fA-F]* which does not point to an object of type 'T'(\n|\r\n|\r)" }
+    // { dg-output "0x\[0-9a-fA-F]*: note: object is of type 'S'(\n|\r\n|\r)" }
+    // { dg-output " .. .. .. ..  .. .. .. .. .. .. .. ..  \[^\n\r]*(\n|\r\n|\r)" }
+    // { dg-output "              \\^~~~~~~~~~~\[^\n\r]*(\n|\r\n|\r)" }
+    // { dg-output "              vptr for 'S'\[^\n\r]*(\n|\r\n|\r)" }
+    case 0x12:
+      return p->g ();
+    // { dg-output "\[^\n\r]*vptr-2.C:82:\[0-9]*: runtime error: member call on address 0x\[0-9a-fA-F]* which does not point to an object of type 'T'(\n|\r\n|\r)" }
+    // { dg-output "0x\[0-9a-fA-F]*: note: object is of type 'S'(\n|\r\n|\r)" }
+    // { dg-output " .. .. .. ..  .. .. .. .. .. .. .. ..  \[^\n\r]*(\n|\r\n|\r)" }
+    // { dg-output "              \\^~~~~~~~~~~\[^\n\r]*(\n|\r\n|\r)" }
+    // { dg-output "              vptr for 'S'\[^\n\r]*(\n|\r\n|\r)" }
+    case 0x13:
+      x = static_cast<T*>(reinterpret_cast<S*>(p));
+      break;
+    // { dg-output "\[^\n\r]*vptr-2.C:89:\[0-9]*: runtime error: downcast of address 0x\[0-9a-fA-F]* which does not point to an object of type 'T'(\n|\r\n|\r)" }
+    // { dg-output "0x\[0-9a-fA-F]*: note: object is of type 'S'(\n|\r\n|\r)" }
+    // { dg-output " .. .. .. ..  .. .. .. .. .. .. .. ..  \[^\n\r]*(\n|\r\n|\r)" }
+    // { dg-output "              \\^~~~~~~~~~~\[^\n\r]*(\n|\r\n|\r)" }
+    // { dg-output "              vptr for 'S'\[^\n\r]*(\n|\r\n|\r)" }
+    case 0x34:
+      return reinterpret_cast<U*>(p)->v() - 2;
+    // { dg-output "\[^\n\r]*vptr-2.C:97:\[0-9]*: runtime error: member call on address 0x\[0-9a-fA-F]* which does not point to an object of type 'U'(\n|\r\n|\r)" }
+    // { dg-output "0x\[0-9a-fA-F]*: note: object is base class subobject at offset 16 within object of type 'U'(\n|\r\n|\r)" { target lp64 } }
+    // { dg-output "0x\[0-9a-fA-F]*: note: object is base class subobject at offset 8 within object of type 'U'(\n|\r\n|\r)" { target ilp32 } }
+    // { dg-output " .. .. .. ..  .. .. .. .. .. .. .. ..  .. .. .. .. .. .. .. ..  .. .. .. .. .. .. .. ..  \[^\n\r]*(\n|\r\n|\r)" }
+    // { dg-output "              \\^                                                 ~~~~~~~~~~~~~~~~~~~~~~~(\n|\r\n|\r)" { target lp64 } }
+    // { dg-output "                                                                vptr for 'T' base class of 'U'\[^\n\r]*(\n|\r\n|\r)" { target lp64 } }
+    // { dg-output "              \\^                        ~~~~~~~~~~~(\n|\r\n|\r)" { target ilp32 } }
+    // { dg-output "                                       vptr for 'T' base class of 'U'\[^\n\r]*(\n|\r\n|\r)" { target ilp32 } }
+    case 0x41:
+      return p->b;
+    // { dg-output "\[^\n\r]*vptr-2.C:107:\[0-9]*: runtime error: member access within address 0x\[0-9a-fA-F]* which does not point to an object of type 'T'(\n|\r\n|\r)" }
+    // { dg-output "0x\[0-9a-fA-F]*: note: object is of type 'U'(\n|\r\n|\r)" }
+    // { dg-output " .. .. .. ..  .. .. .. .. .. .. .. ..  \[^\n\r]*(\n|\r\n|\r)" }
+    // { dg-output "              \\^~~~~~~~~~~\[^\n\r]*(\n|\r\n|\r)" }
+    // { dg-output "              vptr for 'U'\[^\n\r]*(\n|\r\n|\r)" }
+    case 0x42:
+      return p->g ();
+    // { dg-output "\[^\n\r]*vptr-2.C:114:\[0-9]*: runtime error: member call on address 0x\[0-9a-fA-F]* which does not point to an object of type 'T'(\n|\r\n|\r)" }
+    // { dg-output "0x\[0-9a-fA-F]*: note: object is of type 'U'(\n|\r\n|\r)" }
+    // { dg-output " .. .. .. ..  .. .. .. .. .. .. .. ..  \[^\n\r]*(\n|\r\n|\r)" }
+    // { dg-output "              \\^~~~~~~~~~~\[^\n\r]*(\n|\r\n|\r)" }
+    // { dg-output "              vptr for 'U'\[^\n\r]*(\n|\r\n|\r)" }
+    case 0x43:
+      x = static_cast<T*>(reinterpret_cast<S*>(p));
+      break;
+    // { dg-output "\[^\n\r]*vptr-2.C:121:\[0-9]*: runtime error: downcast of address 0x\[0-9a-fA-F]* which does not point to an object of type 'T'(\n|\r\n|\r)" }
+    // { dg-output "0x\[0-9a-fA-F]*: note: object is of type 'U'(\n|\r\n|\r)" }
+    // { dg-output " .. .. .. ..  .. .. .. .. .. .. .. ..  \[^\n\r]*(\n|\r\n|\r)" }
+    // { dg-output "              \\^~~~~~~~~~~\[^\n\r]*(\n|\r\n|\r)" }
+    // { dg-output "              vptr for 'U'\[^\n\r]*(\n|\r\n|\r)" }
+    case 0x51:
+      return p->b;
+    // { dg-output "\[^\n\r]*vptr-2.C:129:\[0-9]*: runtime error: member access within address 0x\[0-9a-fA-F]* which does not point to an object of type 'T'(\n|\r\n|\r)" }
+    // { dg-output "0x\[0-9a-fA-F]*: note: object has invalid vptr(\n|\r\n|\r)" }
+    // { dg-output " .. .. .. ..  00 00 00 00 00 00 00 00  \[^\n\r]*(\n|\r\n|\r)" { target lp64 } }
+    // { dg-output "              \\^~~~~~~~~~~~~~~~~~~~~~~\[^\n\r]*(\n|\r\n|\r)" { target lp64 } }
+    // { dg-output "  ?.. .. .. ..  ?00 00 00 00  ?.. .. .. ..  ?\[^\n\r]*(\n|\r\n|\r)" { target ilp32 } }
+    // { dg-output "              \\^~~~~~~~~~~\[^\n\r]*(\n|\r\n|\r)" { target ilp32 } }
+    // { dg-output "              invalid vptr" }
+    }
+  return 0;
+}
+
+char b[sizeof (U)] __attribute__((aligned (__alignof__ (U)))) = {};
+
+__attribute__((noinline, noclone)) void
+baz (int q)
+{
+  T *p = 0;
+  S *s = 0;
+  U *u = 0;
+  switch (q)
+    {
+    case 0x10: case 0x11: case 0x12: case 0x13:
+      s = new S;
+      bar<S, T, U> (reinterpret_cast<T *>(s), q);
+      delete s;
+      break;
+    case 0x20: case 0x21: case 0x22: case 0x23:
+      p = new T;
+      bar<S, T, U> (p, q);
+      delete p;
+      break;
+    case 0x30: case 0x31: case 0x32: case 0x33: case 0x34:
+      u = new U;
+      bar<S, T, U> (u, q);
+      delete u;
+      break;
+    case 0x40: case 0x41: case 0x42: case 0x43: case 0x44:
+      u = new U;
+      bar<S, T, U> (reinterpret_cast<T *>(u), q);
+      delete u;
+      break;
+    case 0x51:
+      p = reinterpret_cast<T*>(b);
+      bar<S, T, U> (p, q);
+      break;
+    }
+}
+
+int
+main ()
+{
+  foo ();
+  for (int q = 0; q < 0x52; q++)
+    baz (q);
+}
--- gcc/testsuite/g++.dg/ubsan/vptr-6.C.jj	2014-10-27 10:48:06.866096890 +0100
+++ gcc/testsuite/g++.dg/ubsan/vptr-6.C	2014-10-27 21:40:31.619148815 +0100
@@ -0,0 +1,32 @@
+// { dg-do compile }
+// { dg-skip-if "" { *-*-* } { "-flto" } { "" } }
+// { dg-options "-fsanitize=vptr -O2 -fdump-tree-optimized" }
+
+struct S { virtual ~S (); int i; _Complex int j[5]; };
+
+int
+f1 (S *p)
+{
+  return p->i;
+}
+
+int
+f2 (S *p)
+{
+  return *&p->i;
+}
+
+_Complex int *
+f3 (S *p, S *q)
+{
+  return &p->j[q->i];
+}
+
+int
+f4 (S &p, S &q)
+{
+  return __imag__ p.j[q.i];
+}
+
+// { dg-final { scan-tree-dump-times "__ubsan_handle_dynamic_type_cache_miss" 5 "optimized" } }
+// { dg-final { cleanup-tree-dump "optimized" } }
--- gcc/testsuite/g++.dg/ubsan/vptr-1.C.jj	2014-10-27 10:48:06.866096890 +0100
+++ gcc/testsuite/g++.dg/ubsan/vptr-1.C	2014-10-27 10:48:06.866096890 +0100
@@ -0,0 +1,184 @@
+// { dg-do run { target { ilp32 || lp64 } } }
+// { dg-options "-fsanitize=vptr" }
+
+struct S
+{
+  S() : a(0) {}
+  ~S() {}
+  int a;
+  int f() { return 0; }
+  virtual int v() { return 0; }
+};
+  
+struct T : S
+{
+  T() : b(0) {}
+  int b;
+  int g() { return 0; }
+  virtual int v() { return 1; }
+};
+
+struct U : S, T { virtual int v() { return 2; } }; // { dg-warning "direct base .S. inaccessible in .U. due to ambiguity" }
+struct V : S {};
+
+void
+foo ()
+{
+  T t;
+  (void)t.a;
+  (void)t.b;
+  (void)t.f();
+  (void)t.g();
+  (void)t.v();
+  (void)t.S::v();
+    
+  U u;
+  (void)u.T::a;
+  (void)u.b;
+  (void)u.T::f();
+  (void)u.g();
+  (void)u.v();
+  (void)u.T::v();
+  (void)((T&)u).S::v();
+}
+
+T *x;
+
+__attribute__((noinline, noclone)) int
+bar (T *p, int q)
+{
+  switch (q)
+    {
+    // These shouldn't fail:
+    case 0x10:
+    case 0x20:
+    case 0x30:
+    case 0x40:
+      {
+	T &r = *p;
+	break;
+      }
+    case 0x21:
+    case 0x31:
+      return p->b;
+    case 0x22:
+    case 0x32:
+      return p->g ();
+    case 0x23:
+    case 0x33:
+      x = static_cast<T*>(reinterpret_cast<S*>(p));
+      break;
+    case 0x44:
+      return reinterpret_cast<U*>(p)->v() - 2;
+    // These should:
+    case 0x11:
+      return p->b;
+    // { dg-output "\[^\n\r]*vptr-1.C:75:\[0-9]*: runtime error: member access within address 0x\[0-9a-fA-F]* which does not point to an object of type 'T'(\n|\r\n|\r)" }
+    // { dg-output "0x\[0-9a-fA-F]*: note: object is of type 'S'(\n|\r\n|\r)" }
+    // { dg-output " .. .. .. ..  .. .. .. .. .. .. .. ..  \[^\n\r]*(\n|\r\n|\r)" }
+    // { dg-output "              \\^~~~~~~~~~~\[^\n\r]*(\n|\r\n|\r)" }
+    // { dg-output "              vptr for 'S'\[^\n\r]*(\n|\r\n|\r)" }
+    case 0x12:
+      return p->g ();
+    // { dg-output "\[^\n\r]*vptr-1.C:82:\[0-9]*: runtime error: member call on address 0x\[0-9a-fA-F]* which does not point to an object of type 'T'(\n|\r\n|\r)" }
+    // { dg-output "0x\[0-9a-fA-F]*: note: object is of type 'S'(\n|\r\n|\r)" }
+    // { dg-output " .. .. .. ..  .. .. .. .. .. .. .. ..  \[^\n\r]*(\n|\r\n|\r)" }
+    // { dg-output "              \\^~~~~~~~~~~\[^\n\r]*(\n|\r\n|\r)" }
+    // { dg-output "              vptr for 'S'\[^\n\r]*(\n|\r\n|\r)" }
+    case 0x13:
+      x = static_cast<T*>(reinterpret_cast<S*>(p));
+      break;
+    // { dg-output "\[^\n\r]*vptr-1.C:89:\[0-9]*: runtime error: downcast of address 0x\[0-9a-fA-F]* which does not point to an object of type 'T'(\n|\r\n|\r)" }
+    // { dg-output "0x\[0-9a-fA-F]*: note: object is of type 'S'(\n|\r\n|\r)" }
+    // { dg-output " .. .. .. ..  .. .. .. .. .. .. .. ..  \[^\n\r]*(\n|\r\n|\r)" }
+    // { dg-output "              \\^~~~~~~~~~~\[^\n\r]*(\n|\r\n|\r)" }
+    // { dg-output "              vptr for 'S'\[^\n\r]*(\n|\r\n|\r)" }
+    case 0x34:
+      return reinterpret_cast<U*>(p)->v() - 2;
+    // { dg-output "\[^\n\r]*vptr-1.C:97:\[0-9]*: runtime error: member call on address 0x\[0-9a-fA-F]* which does not point to an object of type 'U'(\n|\r\n|\r)" }
+    // { dg-output "0x\[0-9a-fA-F]*: note: object is base class subobject at offset 16 within object of type 'U'(\n|\r\n|\r)" { target lp64 } }
+    // { dg-output "0x\[0-9a-fA-F]*: note: object is base class subobject at offset 8 within object of type 'U'(\n|\r\n|\r)" { target ilp32 } }
+    // { dg-output " .. .. .. ..  .. .. .. .. .. .. .. ..  .. .. .. .. .. .. .. ..  .. .. .. .. .. .. .. ..  \[^\n\r]*(\n|\r\n|\r)" }
+    // { dg-output "              \\^                                                 ~~~~~~~~~~~~~~~~~~~~~~~(\n|\r\n|\r)" { target lp64 } }
+    // { dg-output "                                                                vptr for 'T' base class of 'U'\[^\n\r]*(\n|\r\n|\r)" { target lp64 } }
+    // { dg-output "              \\^                        ~~~~~~~~~~~(\n|\r\n|\r)" { target ilp32 } }
+    // { dg-output "                                       vptr for 'T' base class of 'U'\[^\n\r]*(\n|\r\n|\r)" { target ilp32 } }
+    case 0x41:
+      return p->b;
+    // { dg-output "\[^\n\r]*vptr-1.C:107:\[0-9]*: runtime error: member access within address 0x\[0-9a-fA-F]* which does not point to an object of type 'T'(\n|\r\n|\r)" }
+    // { dg-output "0x\[0-9a-fA-F]*: note: object is of type 'U'(\n|\r\n|\r)" }
+    // { dg-output " .. .. .. ..  .. .. .. .. .. .. .. ..  \[^\n\r]*(\n|\r\n|\r)" }
+    // { dg-output "              \\^~~~~~~~~~~\[^\n\r]*(\n|\r\n|\r)" }
+    // { dg-output "              vptr for 'U'\[^\n\r]*(\n|\r\n|\r)" }
+    case 0x42:
+      return p->g ();
+    // { dg-output "\[^\n\r]*vptr-1.C:114:\[0-9]*: runtime error: member call on address 0x\[0-9a-fA-F]* which does not point to an object of type 'T'(\n|\r\n|\r)" }
+    // { dg-output "0x\[0-9a-fA-F]*: note: object is of type 'U'(\n|\r\n|\r)" }
+    // { dg-output " .. .. .. ..  .. .. .. .. .. .. .. ..  \[^\n\r]*(\n|\r\n|\r)" }
+    // { dg-output "              \\^~~~~~~~~~~\[^\n\r]*(\n|\r\n|\r)" }
+    // { dg-output "              vptr for 'U'\[^\n\r]*(\n|\r\n|\r)" }
+    case 0x43:
+      x = static_cast<T*>(reinterpret_cast<S*>(p));
+      break;
+    // { dg-output "\[^\n\r]*vptr-1.C:121:\[0-9]*: runtime error: downcast of address 0x\[0-9a-fA-F]* which does not point to an object of type 'T'(\n|\r\n|\r)" }
+    // { dg-output "0x\[0-9a-fA-F]*: note: object is of type 'U'(\n|\r\n|\r)" }
+    // { dg-output " .. .. .. ..  .. .. .. .. .. .. .. ..  \[^\n\r]*(\n|\r\n|\r)" }
+    // { dg-output "              \\^~~~~~~~~~~\[^\n\r]*(\n|\r\n|\r)" }
+    // { dg-output "              vptr for 'U'\[^\n\r]*(\n|\r\n|\r)" }
+    case 0x51:
+      return p->b;
+    // { dg-output "\[^\n\r]*vptr-1.C:129:\[0-9]*: runtime error: member access within address 0x\[0-9a-fA-F]* which does not point to an object of type 'T'(\n|\r\n|\r)" }
+    // { dg-output "0x\[0-9a-fA-F]*: note: object has invalid vptr(\n|\r\n|\r)" }
+    // { dg-output " .. .. .. ..  00 00 00 00 00 00 00 00  \[^\n\r]*(\n|\r\n|\r)" { target lp64 } }
+    // { dg-output "              \\^~~~~~~~~~~~~~~~~~~~~~~\[^\n\r]*(\n|\r\n|\r)" { target lp64 } }
+    // { dg-output "  ?.. .. .. ..  ?00 00 00 00  ?.. .. .. ..  ?\[^\n\r]*(\n|\r\n|\r)" { target ilp32 } }
+    // { dg-output "              \\^~~~~~~~~~~\[^\n\r]*(\n|\r\n|\r)" { target ilp32 } }
+    // { dg-output "              invalid vptr" }
+    }
+  return 0;
+}
+
+char b[sizeof (U)] __attribute__((aligned (__alignof__ (U)))) = {};
+
+__attribute__((noinline, noclone)) void
+baz (int q)
+{
+  T *p = 0;
+  S *s = 0;
+  U *u = 0;
+  switch (q)
+    {
+    case 0x10: case 0x11: case 0x12: case 0x13:
+      s = new S;
+      bar (reinterpret_cast<T *>(s), q);
+      delete s;
+      break;
+    case 0x20: case 0x21: case 0x22: case 0x23:
+      p = new T;
+      bar (p, q);
+      delete p;
+      break;
+    case 0x30: case 0x31: case 0x32: case 0x33: case 0x34:
+      u = new U;
+      bar (u, q);
+      delete u;
+      break;
+    case 0x40: case 0x41: case 0x42: case 0x43: case 0x44:
+      u = new U;
+      bar (reinterpret_cast<T *>(u), q);
+      delete u;
+      break;
+    case 0x51:
+      p = reinterpret_cast<T*>(b);
+      bar (p, q);
+      break;
+    }
+}
+
+int
+main ()
+{
+  foo ();
+  for (int q = 0; q < 0x52; q++)
+    baz (q);
+}
--- libsanitizer/ubsan/ubsan_handlers.cc.jj	2014-09-24 11:08:04.184026152 +0200
+++ libsanitizer/ubsan/ubsan_handlers.cc	2014-10-27 12:22:34.151570646 +0100
@@ -28,10 +28,10 @@ static bool ignoreReport(SourceLocation
 }
 
 namespace __ubsan {
-  const char *TypeCheckKinds[] = {
+const char *TypeCheckKinds[] = {
     "load of", "store to", "reference binding to", "member access within",
-    "member call on", "constructor call on", "downcast of", "downcast of"
-  };
+    "member call on", "constructor call on", "downcast of", "downcast of",
+    "upcast of", "cast to virtual base of"};
 }
 
 static void handleTypeMismatchImpl(TypeMismatchData *Data, ValueHandle Pointer,


	Jakub


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