diff mbox

-fsanitize=vptr instrumentation (take 2)

Message ID 20141027161605.GX10376@tucnak.redhat.com
State New
Headers show

Commit Message

Jakub Jelinek Oct. 27, 2014, 4:16 p.m. UTC
On Wed, Sep 17, 2014 at 10:27:02AM -0400, Jason Merrill wrote:
> On 09/16/2014 10:56 AM, Jakub Jelinek wrote:
> >vptr-5.C is one Jason mailed me yesterday, clang++ doesn't instrument this
> >and g++ right now doesn't either, build_static_cast_1 certainly isn't called
> >in that case, and I must say I have no idea what should be checked there,
> >where etc.
> 
> What needs to be checked is conversion (in this case implicit) to a virtual
> base; if the vptr doesn't point to a vtable that has the appropriate vbase
> offset, we should complain.
> 
> virtual base conversions are implemented in build_base_path under if
> (virtual_access).

Implemented now.

> >vptr-6.C shows where the this optimization is performed and where it isn't
> >(clang++ has 10 instrumentations in T::h and 1 in S::l, g++ has fewer than
> >that, but not 0 in T::h (1 in S::l is right and needed I think)).
> 
> I agree that 0 is enough for T::h and 1 for S::l.

Based on the further discussions, I've dropped the this optimizations,
perhaps we can tweak the sanopt pass to optimize some unnecessary checks
later on.

> >I hope all of f[1-6] is invalid, I really don't see how we could instrument
> >member accesses otherwise (we'd need to limit to not taking address of it);
> >NULL pointer shouldn't point at a valid object.

Based on the discussions, I'm not instrumenting &p->a or &*&p->a for now,
am instrumenting just p->a or *&p->a.  Until the WG decides what to do with
DR597/DR1531.

> I don't see anything in the standard saying that these are undefined, only
> that trying to access the (non-)object pointed to is undefined.  It would be
> undefined if a conversion to virtual base were involved, i.e.
> 
> struct V: virtual R { };
> 
> // undefined if p doesn't point to a V because of the conversion to
> // virtual base R
> int* f7 (V* p) { return &p->r; }

Yeah, this is instrumented now (including complaining if p is NULL here).

> These conditions were loosened in C++11 by DRs 597 and 1531; before that it
> was reasonable to regard f[1-6] as undefined, and perhaps clang is using the
> earlier interpretation.
> 
> >+  TREE_SIDE_EFFECTS (cond) = 1;
> ...
> >+  TREE_SIDE_EFFECTS (hash) = 1;
> 
> Why do you need to set TREE_SIDE_EFFECTS on these?

Not needed, dropped now.

> >+  if (current_function_decl == NULL_TREE
> >+      || lookup_attribute ("no_sanitize_undefined",
> >+			   DECL_ATTRIBUTES (current_function_decl)))
> >+    return NULL_TREE;
> 
> When would this be called outside a function?  If for namespace-scope
> variable initializers, I'd think we do want instrumentation.

Changed.

> >+  /* 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;
> 
> You might want to use resolves_to_fixed_type_p in the optimizations.

For now I'd prefer not to do further optimizations, until it is clear that
those optimizations wouldn't remove any checks that could trigger on invalid
programs.

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'
)?

I haven't implemented the upcast checks Alex Samsonov implemented in clang recently,
those aren't -fsanitize=vptr but -fsanitize=alignment and/or
-fsanitize=object-size, so can be done in an incremental patch.

Furthermore, not 100% sure there if say given:
struct S { int a; };
struct T : S { int b[1024]; };
S *foo (T *p) { return (S *) p; }
it is really undefined behavior if p (if not NULL) doesn't point to object
that has at least sizeof (T) bytes in it.  Where does C++ say that e.g.:
S *bar () { S s; return foo ((T *) &s); }
is undefined behavior (assuming the alignment is right)?
struct U { S s; int b[1024]; };
S *foo2 (U *p) { return (S *) p; }
S *bar2 () { S s; return foo2 ((U *) &s); }
is not instrumented and not undefined behavior (again, assuming the
alignment is right)?  I have in mind the common technique where even in GCC
sources e.g. for tree_node union we sometimes allocate smaller sizes (just
to cover the size of some union field), instead of whole union, or
allocating space just for parts of a structure (e.g. if there is a trailing
foo[1] array, allocation size can be done for offsetof(type, foo[0]) etc.).

2014-10-27  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.
	(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.



	Jakub
diff mbox

Patch

--- 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 10:48:06.858097045 +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,59 @@  cp_genericize_r (tree *stmt_p, int *walk
   return NULL;
 }
 
+/* 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;
+  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;
+	  cp_walk_tree (&t, cp_ubsan_check_member_access_r,
+			(void *) stmt, NULL);
+	}
+      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, NULL, NULL);
+	}
+      break;
+    case COMPONENT_REF:
+      if (data == NULL)
+	cp_ubsan_maybe_instrument_member_access (stmt);
+      /* FALLTHRU */
+    default:
+      if (data && handled_component_p (stmt))
+	{
+	  int i, len = TREE_OPERAND_LENGTH (stmt);
+	  *walk_subtrees = 0;
+	  if (!handled_component_p (TREE_OPERAND (stmt, 0)))
+	    data = NULL;
+	  for (i = 0; i < len; i++)
+	    {
+	      cp_walk_tree (&TREE_OPERAND (stmt, i),
+			    cp_ubsan_check_member_access_r, data, NULL);
+	      data = NULL;
+	    }
+	}
+      break;
+    }
+  return NULL_TREE;
+}
+
 /* Lower C++ front end trees to GENERIC in T_P.  */
 
 static void
@@ -1233,6 +1307,8 @@  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)
+    cp_walk_tree (t_p, cp_ubsan_check_member_access_r, NULL, NULL);
 }
 
 /* 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,291 @@ 
+/* 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_STATIC (array) = 1;
+      DECL_EXTERNAL (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 10:48:06.865096910 +0100
@@ -0,0 +1,25 @@ 
+// { dg-do compile }
+// { 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 10:48:06.866096890 +0100
@@ -0,0 +1,31 @@ 
+// { dg-do compile }
+// { 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,