public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH, updated] Vtable pointer verification, main gcc changes (patch 2 of 3)
@ 2013-02-25 19:28 Caroline Tice
  2013-03-07 23:55 ` Caroline Tice
  2013-03-13 17:48 ` Diego Novillo
  0 siblings, 2 replies; 4+ messages in thread
From: Caroline Tice @ 2013-02-25 19:28 UTC (permalink / raw)
  To: GCC Patches
  Cc: Diego Novillo, Luis Lozano, Bhaskar Janakiraman, Caroline Tice

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

Here are the latest changes to the vtable pointer verification patches
(again there are 3 patches: c++ front end, main gcc, and c++ runtime
library).  I think these address all the review comments I have
received so far.  This patch is the for main gcc.  Please review these
changes and let me know if they will be ok to commit once stage 1
opens.

-- Caroline Tice
cmtice@google.com

2013-02-25  Caroline Tice  <cmtice@google.com>

	* configure (CXX_FOR_TARGET): Add libstdc++-v3/libsupc++/.libs to the
	library search path.
	* ligbcc/config.host (extra_parts):  Add vtv_start.o and vtv_end.o to
	the list.
	* libgcc/Makefile.in: Add definitin for gcc_srcdir; add rules for
	building vtv_start.o and vtv_end.o.
	* passes.c (init_optimization_pass): Add pass_vtable_verify.
	* vtv_start.c:  New file.
	* tree-pass.h (pass_vtable_verify): Declare new pass.
	* tree-vtable-verify.c:  New file, contains vtable verification tree
	pass.
	* tree-vtable-verify.h: New file.
	* common.opt: (fvtable-verify=): New option. Also define vtv_priority
	values for the option.
	* timevar.def (TV_VTABLE_VERIFICATION):  Declare new time var.
	* config/gnu-user.h: Add vtv_start.o to STARTFILE_SPEC if
	fvtable-verify is present; Add vtv_end.o to ENDFILE_SPEC if
	fvtable-verify is present.
	* tree.h: Add extern function declaration for save_vtable_map_decl.
	* vtv_end.c:  New file.
	* flag-types.h (vtv_priority):  New enum, for values for new
	'-fvtable-verify=' option.
	* Makefile.in (OBJS):  Add tree-vtable-verify.o to list of object
	files.
	(tree-vtable-verify.o):  Add rule for building object file.
	(GTFILES): Add tree-vtable-verify.c to list of files that use GCC's
	garbage collector.
	* varasm.c (assemble_variable): Add code for handling variables that
	go into the ".vtable_map_vars" section.
	(assemble_vtv_perinit_initializer):  New function.
	(default_section_type_flags):  Add SECTION_LINKONCE to
	".vtable_map_vars" section items.
	* output.h (assemble_vtv_preinit_initializer):  External function decl.

[-- Attachment #2: fsf-vtable-verification.v5.gcc-main.patch --]
[-- Type: application/octet-stream, Size: 52354 bytes --]

Index: configure
===================================================================
--- configure	(revision 196266)
+++ configure	(working copy)
@@ -13741,7 +13741,7 @@ else
   esac
   if test $ok = yes; then
     # An in-tree tool is available and we can use it
-    CXX_FOR_TARGET='$$r/$(HOST_SUBDIR)/gcc/xg++ -B$$r/$(HOST_SUBDIR)/gcc/ -nostdinc++ `if test -f $$r/$(TARGET_SUBDIR)/libstdc++-v3/scripts/testsuite_flags; then $(SHELL) $$r/$(TARGET_SUBDIR)/libstdc++-v3/scripts/testsuite_flags --build-includes; else echo -funconfigured-libstdc++-v3 ; fi` -L$$r/$(TARGET_SUBDIR)/libstdc++-v3/src -L$$r/$(TARGET_SUBDIR)/libstdc++-v3/src/.libs'
+    CXX_FOR_TARGET='$$r/$(HOST_SUBDIR)/gcc/xg++ -B$$r/$(HOST_SUBDIR)/gcc/ -nostdinc++ `if test -f $$r/$(TARGET_SUBDIR)/libstdc++-v3/scripts/testsuite_flags; then $(SHELL) $$r/$(TARGET_SUBDIR)/libstdc++-v3/scripts/testsuite_flags --build-includes; else echo -funconfigured-libstdc++-v3 ; fi` -L$$r/$(TARGET_SUBDIR)/libstdc++-v3/src -L$$r/$(TARGET_SUBDIR)/libstdc++-v3/src/.libs -L$$r/$(TARGET_SUBDIR)/libstdc++-v3/libsupc++/.libs'
     { $as_echo "$as_me:${as_lineno-$LINENO}: result: just compiled" >&5
 $as_echo "just compiled" >&6; }
   elif expr "x$CXX_FOR_TARGET" : "x/" > /dev/null; then
@@ -13786,7 +13786,7 @@ else
   esac
   if test $ok = yes; then
     # An in-tree tool is available and we can use it
-    RAW_CXX_FOR_TARGET='$$r/$(HOST_SUBDIR)/gcc/xgcc -shared-libgcc -B$$r/$(HOST_SUBDIR)/gcc -nostdinc++ -L$$r/$(TARGET_SUBDIR)/libstdc++-v3/src -L$$r/$(TARGET_SUBDIR)/libstdc++-v3/src/.libs'
+    RAW_CXX_FOR_TARGET='$$r/$(HOST_SUBDIR)/gcc/xgcc -shared-libgcc -B$$r/$(HOST_SUBDIR)/gcc -nostdinc++ -L$$r/$(TARGET_SUBDIR)/libstdc++-v3/src -L$$r/$(TARGET_SUBDIR)/libstdc++-v3/src/.libs -L$$r/$(TARGET_SUBDIR)/libstdc++-v3/libsupc++/.libs'
     { $as_echo "$as_me:${as_lineno-$LINENO}: result: just compiled" >&5
 $as_echo "just compiled" >&6; }
   elif expr "x$RAW_CXX_FOR_TARGET" : "x/" > /dev/null; then
Index: libgcc/config.host
===================================================================
--- libgcc/config.host	(revision 196266)
+++ libgcc/config.host	(working copy)
@@ -197,7 +197,7 @@ case ${host} in
   ;;
 *-*-linux* | frv-*-*linux* | *-*-kfreebsd*-gnu | *-*-knetbsd*-gnu | *-*-gnu* | *-*-kopensolaris*-gnu)
   tmake_file="$tmake_file t-crtstuff-pic t-libgcc-pic t-eh-dw2-dip t-slibgcc t-slibgcc-gld t-slibgcc-elf-ver t-linux"
-  extra_parts="crtbegin.o crtbeginS.o crtbeginT.o crtend.o crtendS.o"
+  extra_parts="crtbegin.o crtbeginS.o crtbeginT.o crtend.o crtendS.o vtv_start.o vtv_end.o"
   ;;
 *-*-lynxos*)
   tmake_file="$tmake_file t-lynx $cpu_type/t-crtstuff t-crtstuff-pic t-libgcc-pic"
Index: libgcc/Makefile.in
===================================================================
--- libgcc/Makefile.in	(revision 196266)
+++ libgcc/Makefile.in	(working copy)
@@ -22,6 +22,7 @@
 libgcc_topdir = @libgcc_topdir@
 host_subdir = @host_subdir@
 
+gcc_srcdir = $(libgcc_topdir)/gcc
 gcc_objdir = $(MULTIBUILDTOP)../../$(host_subdir)/gcc
 
 srcdir = @srcdir@
@@ -969,6 +970,16 @@ crtendS$(objext): $(srcdir)/crtstuff.c
 # This is a version of crtbegin for -static links.
 crtbeginT$(objext): $(srcdir)/crtstuff.c
 	$(crt_compile) $(CRTSTUFF_T_CFLAGS) -c $< -DCRT_BEGIN -DCRTSTUFFT_O
+
+# These are used in vtable verification; see comments in source files for
+# more details.
+vtv_start$(objext): $(gcc_srcdir)/vtv_start.c
+	$(crt_compile) $(CRTSTUFF_T_CFLAGS_S) \
+	  -c $(gcc_srcdir)/vtv_start.c
+
+vtv_end$(objext): $(gcc_srcdir)/vtv_end.c
+	$(crt_compile) $(CRTSTUFF_T_CFLAGS_S) \
+	  -c $(gcc_srcdir)/vtv_end.c
 endif
 
 ifeq ($(CUSTOM_CRTIN),)
Index: gcc/passes.c
===================================================================
--- gcc/passes.c	(revision 196266)
+++ gcc/passes.c	(working copy)
@@ -1554,6 +1554,7 @@ init_optimization_passes (void)
       NEXT_PASS (pass_tm_memopt);
       NEXT_PASS (pass_tm_edges);
     }
+  NEXT_PASS (pass_vtable_verify);
   NEXT_PASS (pass_lower_complex_O0);
   NEXT_PASS (pass_asan_O0);
   NEXT_PASS (pass_tsan_O0);
Index: gcc/vtv_start.c
===================================================================
--- gcc/vtv_start.c	(revision 0)
+++ gcc/vtv_start.c	(revision 0)
@@ -0,0 +1,60 @@
+/*  Copyright (C) 2012, 2013
+    Free Software Foundation, Inc.
+
+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/>.  */
+
+/* This file is part of the vtable verification feature (for a
+   detailed description of the feature, see comments in
+   tree-vtable-verify.c).  The vtable verification feature creates
+   certain global symbols that need to be read-write sometimes during
+   program execution, and read-only at others.  It uses 'mprotect' to
+   change the memory protections of the pages on which these variables
+   are stored.  In order to not affect the protections of other
+   program variables, these variables are put into a special named
+   section, ".vtable_map_vars", which is page-aligned at the start,
+   and which is padded with a page-sized amount of zeros at the end.
+   To make this section page aligned, we create a special symbol,
+   "_vtable_map_vars_start" which we make the very first thing that
+   goes into the section.  This file defines that symbol (and only
+   that symbol).  GCC compiles this file into vtv_start.o, and
+   inserts vtv_start.o into the link line immediately after
+   crtbegin.o, if the program is compiled with -fvtable.verify.
+
+   In order to pad the ".vtable_map_vars" section with a page-sized
+   amount of zeros at the end, there is a second symbol,
+   _vtable_map_vars_end, which is defined in another file, vtv_end.c.
+   This second symbol is a page-sized array of chars, zero-filled, and
+   is the very last thing to go into the section.  When the GCC driver
+   inserts vtv_start.o into the link line (just after crtbegin.o) it
+   also inserts vtv_end.o into the link line, just before crtend.o.
+   This has the desired effect of making our section page-aligned and
+   page-size paded, ensuring that no other program data lands on our
+   pages.  */
+
+#define PAGE_SIZE 4096
+
+#ifdef BIG_PAGE_SIZE
+/* TODO - Replace '4096' below with correct big page size.  */
+#define PAGE_SIZE 4096
+#endif
+
+
+/* Page-aligned symbol to mark beginning of .vtable_map_vars section.  */
+char _vtable_map_vars_start []
+__attribute__ ((__visibility__ ("protected"), used, aligned(PAGE_SIZE),
+		section(".vtable_map_vars")))
+  = { };
Index: gcc/tree-pass.h
===================================================================
--- gcc/tree-pass.h	(revision 196266)
+++ gcc/tree-pass.h	(working copy)
@@ -364,6 +364,7 @@ extern struct gimple_opt_pass pass_tm_ed
 extern struct gimple_opt_pass pass_split_functions;
 extern struct gimple_opt_pass pass_feedback_split_functions;
 extern struct gimple_opt_pass pass_strength_reduction;
+extern struct gimple_opt_pass pass_vtable_verify;
 
 /* IPA Passes */
 extern struct simple_ipa_opt_pass pass_ipa_lower_emutls;
Index: gcc/tree-vtable-verify.c
===================================================================
--- gcc/tree-vtable-verify.c	(revision 0)
+++ gcc/tree-vtable-verify.c	(revision 0)
@@ -0,0 +1,724 @@
+/*   Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011
+    Free Software Foundation, Inc.
+
+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/>.  */
+
+/* Virtual Table Pointer Security Pass - Detect corruption of vtable pointers
+   before using them for virtual method dispatches.  */
+
+/* This file is part of the vtable security feature implementation.
+   The vtable security feature is designed to detect when a virtual
+   call is about to be made through an invalid vtable pointer
+   (possibly due to data corruption or malicious attacks). The
+   compiler finds every virtual call, and inserts a verification call
+   before the virtual call.  The verification call takes the actual
+   vtable pointer value in the object through which the virtual call
+   is being made, and compares the vtable pointer against a set of all
+   valid vtable pointers that the object could contain (this set is
+   based on the declared type of the object).  If the pointer is in
+   the valid set, execution is allowed to continue; otherwise the
+   program is halted.
+
+  There are several pieces needed in order to make this work: 1. For
+  every virtual class in the program (i.e. a class that contains
+  virtual methods), we need to build the set of all possible valid
+  vtables that an object of that class could point to.  This includes
+  vtables for any class(es) that inherit from the class under
+  consideration.  2. For every such data set we build up, we need a
+  way to find and reference the data set.  This is complicated by the
+  fact that the real vtable addresses are not known until runtime,
+  when the program is loaded into memory, but we need to reference the
+  sets at compile time when we are inserting verification calls into
+  the program.  3.  We need to find every virtual call in the program,
+  and insert the verification call (with the appropriate arguments)
+  before the virtual call.  4. We need some runtime library pieces:
+  the code to build up the data sets at runtime; the code to actually
+  perform the verification using the data sets; and some code to set
+  protections on the data sets, so they themselves do not become
+  hacker targets.
+
+  To find and reference the set of valid vtable pointers for any given
+  virtual class, we create a special global varible for each virtual
+  class.  We refer to this as the "vtable map variable" for that
+  class.  The vtable map variable has the type "void *", and is
+  initialized by the compiler to NULL.  At runtime when the set of
+  valid vtable pointers for a virtual class, e.g. class Foo, is built,
+  the vtable map variable for class Foo is made to point to the set.
+  During compile time, when the compiler is inserting verification
+  calls into the program, it passes the vtable map variable for the
+  appropriate class to the verification call, so that at runtime the
+  verification call can find the appropriate data set.
+
+  The actual set of valid vtable pointers for a virtual class,
+  e.g. class Foo, cannot be built until runtime, when the vtables get
+  loaded into memory and their addresses are known.  But the knowledge
+  about which vtables belong in which class' hierarchy is only known
+  at compile time.  Therefore at compile time we collect class
+  hierarchy and vtable information about every virtual class, and we
+  generate calls to build up the data sets at runtime.  To build the
+  data sets, we call one of the functions we add to the runtime
+  library, __VLTRegisterPair.  __VLTRegisterPair takes two arguments,
+  a vtable map variable and the address of a vtable.  If the vtable
+  map variable is currently NULL, it creates a new data set (hash
+  table), makes the vtable map variable point to the new data set, and
+  inserts the vtable address into the data set.  If the vtable map
+  variable is not NULL, it just inserts the vtable address into the
+  data set.  In order to make sure that our data sets are built before
+  any verification calls happen, we create a special constructor
+  initialization function for each compilation unit, give it a very
+  high initialization priority, and insert all of our calls to
+  __VLTRegisterPair into our special constructor initialization
+  function.
+
+  The vtable verification feature is controlled by the flag
+  '-fvtable-verify='.  There are three flavors of this:
+  '-fvtable-verify=std', '-fvtable-verify=preinit', and
+  '-fvtable-verify=none'.  If the option '-fvtable-verfy=preinit' is
+  used, then our constructor initialization function gets put into the
+  preinit array.  This is necessary if there are data sets that need
+  to be built very early in execution.  If the constructor
+  initialization function gets put into the preinit array, the we also
+  add calls to __VLTChangePermission at the beginning and end of the
+  function.  The call at the beginning sets the permissions on the
+  data sets and vtable map variables to read/write, and the one at the
+  end makes them read-only.  If the '-fvtable-verify=std' option is
+  used, the constructor initialization functions are executed at their
+  normal time, and the __VLTChangePermission calls are handled
+  differently (see the comments in libstdc++-v3/libsupc++/vtv_rts.cc).
+  The option '-fvtable-verify=none' turns off vtable verification.
+
+  This file contains code for the tree pass that goes through all the
+  statements in each basic block, looking for virtual calls, and
+  inserting a call to __VLTVerifyVtablePointer (with appropriate
+  arguments) before each one.  It also contains the hash table
+  functions for the data structures used for collecting the class
+  hierarchy data and building/maintaining the vtable map variable data
+  are defined in gcc/tree-vtable-verify.h.  These data structures are
+  shared with the code in the C++ front end that collects the class
+  hierarchy & vtable information and generates the vtable map
+  variables (see cp/vtable-class-hierarchy.c).  This tree pass should
+  run just before the gimple is converted to RTL.
+
+  Some implementation details for this pass:
+
+  To find the all of the virtual calls, we iterate through all the
+  gimple statements in each basic block, looking for any call
+  statement with the code "OBJ_TYPE_REF".  Once we have found the
+  virtual call, we need to find the vtable pointer through which the
+  call is being made, and the type of the object containing the
+  pointer (to find the appropriate vtable map variable).  We then use
+  these to build a call to __VLTVerifyVtablePointer, passing the
+  vtable map variable, and the vtable pointer.  We insert the
+  verification call just after the gimple statement that gets the
+  vtable pointer out of the object, and we update the next
+  statement to depend on the result returned from
+  __VLTVerifyVtablePointer (the vtable pointer value), to ensure
+  subsequent compiler phases don't remove or reorder the call (it's no
+  good to have the verification occur after the virtual call, for
+  example).  To find the vtable pointer being used (and the type of
+  the object) we search backwards through the def_stmts chain from the
+  virtual call (see verify_bb_vtables for more details).  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "tree.h"
+#include "tm_p.h"
+#include "basic-block.h"
+#include "output.h"
+#include "tree-flow.h"
+#include "tree-dump.h"
+#include "tree-pass.h"
+#include "timevar.h"
+#include "cfgloop.h"
+#include "flags.h"
+#include "tree-inline.h"
+#include "tree-scalar-evolution.h"
+#include "diagnostic-core.h"
+#include "gimple-pretty-print.h"
+#include "toplev.h"
+#include "langhooks.h"
+#include "tree-ssa-propagate.h"
+
+#include "tree-vtable-verify.h"
+
+bool vtv_debug = false;
+unsigned num_vtable_map_nodes = 0;
+bool any_verification_calls_generated = false;
+
+extern GTY(()) tree verify_vtbl_ptr_fndecl;
+tree verify_vtbl_ptr_fndecl = NULL_TREE;
+
+unsigned int vtable_verify_main (void);
+
+/* The following few functions are for the vtbl pointer hash table
+   in the 'registered' field of the struct vtable_map_node.  The hash
+   table keeps track of which vtable pointers have been used in
+   calls to __VLTRegisterPair with that particular vtable map variable.  */
+
+/* This function checks to see if a particular VTABLE_DECL and OFFSET are
+   already in the 'registered' hash table for NODE.  */
+
+bool
+vtbl_map_node_registration_find (struct vtbl_map_node *node,
+                                 tree vtable_decl,
+                                 unsigned offset)
+{
+  struct vtable_registration key;
+  struct vtable_registration **slot;
+
+  gcc_assert (node && node->registered);
+
+  key.vtable_decl = vtable_decl;
+  slot = (struct vtable_registration **) htab_find_slot (node->registered,
+                                                         &key, NO_INSERT);
+
+  if (slot && (*slot))
+    {
+      unsigned i;
+      for (i = 0; i < ((*slot)->offsets).length(); ++i)
+        if ((*slot)->offsets[i] == offset)
+          return true;
+    }
+
+  return false;
+}
+
+/* This function inserts VTABLE_DECL and OFFSET into the 'registered'
+   hash table for NODE.  It returns a boolean indicating whether or not
+   it actually inserted anything.  */
+
+bool
+vtbl_map_node_registration_insert (struct vtbl_map_node *node,
+                                   tree vtable_decl,
+                                   unsigned offset)
+{
+  struct vtable_registration key;
+  struct vtable_registration **slot;
+  bool inserted_something = false;
+
+  if (!node || !node->registered)
+    return false;
+
+  key.vtable_decl = vtable_decl;
+  slot = (struct vtable_registration **) htab_find_slot (node->registered,
+                                                         &key, INSERT);
+
+  if (! *slot)
+    {
+      struct vtable_registration *node;
+      node = XNEW (struct vtable_registration);
+      node->vtable_decl = vtable_decl;
+
+      (node->offsets).create (10);
+      (node->offsets).safe_push (offset);
+      *slot = node;
+      inserted_something = true;
+    }
+  else
+    {
+      /* We found the vtable_decl slot; we need to see if it already
+         contains the offset.  If not, we need to add the offset.  */
+      unsigned i;
+      bool found = false;
+      for (i = 0; i < ((*slot)->offsets).length() && !found; ++i)
+        if ((*slot)->offsets[i] == offset)
+          found = true;
+
+      if (!found)
+        {
+          ((*slot)->offsets).safe_push (offset);
+          inserted_something = true;
+        }
+     }
+  return inserted_something;
+}
+
+/* Hashtable functions for vtable_registration hashtables.  */
+
+static hashval_t
+hash_vtable_registration (const void *p)
+{
+  const struct vtable_registration *n = (const struct vtable_registration *) p;
+  return (hashval_t) (DECL_UID (n->vtable_decl));
+}
+
+static int
+eq_vtable_registration (const void *p1, const void *p2)
+{
+  const struct vtable_registration *n1 =
+                                    (const struct vtable_registration *) p1;
+  const struct vtable_registration *n2 =
+                                    (const struct vtable_registration *) p2;
+  return (DECL_UID (n1->vtable_decl) == DECL_UID (n2->vtable_decl));
+}
+
+/* End of hashtable functions for "registered" hashtables.  */
+
+
+/* Here are the three two structures into which we insert vtable map nodes.
+   We use two data structures because of the vastly different ways we need
+   to find the nodes for various tasks (see comments in tree-vtable-verify.h
+   for more details.  */
+
+/* Vtable map variable nodes stored in a hash table.  */
+static htab_t vtbl_map_hash = NULL;
+
+/* Vtable map variable nodes stored in a vector.  */
+vec<struct vtbl_map_node *> vtbl_map_nodes_vec;
+
+
+/* Hashtable functions for vtbl_map_hash.  */
+
+/* Returns a hash code for P.  */
+
+static hashval_t
+hash_vtbl_map_node (const void *p)
+{
+  const struct vtbl_map_node *n = (const struct vtbl_map_node *) p;
+  return (hashval_t) IDENTIFIER_HASH_VALUE (n->class_name);
+}
+
+/* Returns nonzero if P1 and P2 are equal.  */
+
+static int
+eq_vtbl_map_node (const void *p1, const void *p2)
+{
+  const struct vtbl_map_node *n1 = (const struct vtbl_map_node *) p1;
+  const struct vtbl_map_node *n2 = (const struct vtbl_map_node *) p2;
+  return (IDENTIFIER_HASH_VALUE (n1->class_name) ==
+          IDENTIFIER_HASH_VALUE (n2->class_name));
+}
+
+/* Return vtbl_map node for CLASS_NAME  without creating a new one.  */
+
+struct vtbl_map_node *
+vtbl_map_get_node (tree class_type)
+{
+  struct vtbl_map_node key;
+  struct vtbl_map_node **slot;
+
+  tree class_type_decl;
+  tree class_name;
+  unsigned int type_quals;
+
+  if (!vtbl_map_hash)
+    return NULL;
+
+  gcc_assert (TREE_CODE (class_type) == RECORD_TYPE);
+
+
+  /* Find the TYPE_DECL for the class.  */
+  class_type_decl = TYPE_NAME (class_type);
+
+  /* Verify that there aren't any qualifiers on the type.  */
+  type_quals = TYPE_QUALS (TREE_TYPE (class_type_decl));
+  gcc_assert (type_quals == TYPE_UNQUALIFIED);
+
+  /* Get the mangled name for the unqualified type.  */
+  class_name = DECL_ASSEMBLER_NAME (class_type_decl);
+
+  key.class_name = class_name;
+  slot = (struct vtbl_map_node **) htab_find_slot (vtbl_map_hash, &key,
+                                                   NO_INSERT);
+  if (!slot)
+    return NULL;
+  return *slot;
+}
+
+/* Return vtbl_map node assigned to BASE_CLASS_TYPE.  Create new one
+   when needed.  */
+
+struct vtbl_map_node *
+find_or_create_vtbl_map_node (tree base_class_type)
+{
+  struct vtbl_map_node key;
+  struct vtbl_map_node *node;
+  struct vtbl_map_node **slot;
+  tree class_type_decl;
+  unsigned int type_quals;
+
+  if (!vtbl_map_hash)
+    vtbl_map_hash = htab_create (10, hash_vtbl_map_node,
+                                 eq_vtbl_map_node, NULL);
+
+  /* Find the TYPE_DECL for the class.  */
+  class_type_decl = TYPE_NAME (base_class_type);
+
+  /* Verify that there aren't any type qualifiers on type.  */
+  type_quals = TYPE_QUALS (TREE_TYPE (class_type_decl));
+  gcc_assert (type_quals == TYPE_UNQUALIFIED);
+
+  key.class_name = DECL_ASSEMBLER_NAME (class_type_decl);
+  slot = (struct vtbl_map_node **) htab_find_slot (vtbl_map_hash, &key,
+                                                   INSERT);
+
+  if (*slot)
+    return *slot;
+
+  node = XNEW (struct vtbl_map_node);
+  node->vtbl_map_decl = NULL_TREE;
+  node->class_name = key.class_name;
+  node->uid = num_vtable_map_nodes++;
+
+  node->class_info = XNEW (struct vtv_graph_node);
+  node->class_info->class_type = base_class_type;
+  node->class_info->class_uid = node->uid;
+  node->class_info->num_processed_children = 0;
+
+  (node->class_info->parents).create (4);
+  (node->class_info->children).create (4);
+
+  node->registered = htab_create (16, hash_vtable_registration,
+                                  eq_vtable_registration, NULL);
+  node->is_used = false;
+
+  vtbl_map_nodes_vec.safe_push (node);
+  gcc_assert (vtbl_map_nodes_vec[node->uid] == node);
+
+  *slot = node;
+  return node;
+}
+
+/* End of hashtable functions for vtable_map variables hash table.   */
+
+/* Given a gimple STMT, this function checks to see if the statement
+   is an assignment, the rhs of which is getting the vtable pointer
+   value out of an object.  (i.e. it's the value we need to verify
+   because its the vtable pointer that will be used for a virtual
+   call).  */
+
+static bool
+is_vtable_assignment_stmt (gimple stmt)
+{
+
+  if (gimple_code (stmt) != GIMPLE_ASSIGN)
+    return false;
+  else
+    {
+      tree lhs = gimple_assign_lhs (stmt);
+      tree rhs = gimple_assign_rhs1 (stmt);
+
+      if (TREE_CODE (lhs) != SSA_NAME)
+        return false;
+
+      if (TREE_CODE (rhs) != COMPONENT_REF)
+        return false;
+
+      if (! (TREE_OPERAND (rhs, 1))
+          || (TREE_CODE (TREE_OPERAND (rhs, 1)) != FIELD_DECL))
+        return false;
+
+      if (! DECL_VIRTUAL_P (TREE_OPERAND (rhs, 1)))
+        return false;
+    }
+
+    return true;
+}
+
+/* This function attempts to recover the declared class of an object
+   that is used in making a virtual call.  We try to get the type from
+   the type cast in the gimple assignment statement that extracts the
+   vtable pointer from the object (DEF_STMT).  The gimple statment
+   usually looks something like this:
+
+   D.2201_4 = MEM[(struct Event *)this_1(D)]._vptr.Event    */
+
+static tree
+/* extract_object_class_type (gimple def_stmt) */
+extract_object_class_type (tree rhs)
+{
+  /* tree rhs = NULL_TREE; */
+
+  /* Try to find and extract the type cast from that stmt.  */
+
+  /* rhs = gimple_assign_rhs1 (def_stmt); */
+  /*
+  if (TREE_CODE (rhs) == COMPONENT_REF)
+    {
+      while (TREE_CODE (rhs) == COMPONENT_REF
+             && (TREE_CODE (TREE_OPERAND (rhs, 0)) == COMPONENT_REF))
+        rhs = TREE_OPERAND (rhs, 0);
+
+      if (TREE_CODE (rhs) == COMPONENT_REF
+          && TREE_CODE (TREE_OPERAND (rhs, 0)) == MEM_REF
+          && TREE_CODE (TREE_TYPE (TREE_OPERAND (rhs, 0)))== RECORD_TYPE)
+        rhs = TREE_TYPE (TREE_OPERAND (rhs, 0));
+      else
+        rhs = NULL_TREE;
+    }
+  else
+    rhs = NULL_TREE;
+  */
+
+  tree result = NULL_TREE;
+
+
+  if (TREE_CODE (rhs) == COMPONENT_REF)
+    {
+      tree op0 = TREE_OPERAND (rhs, 0);
+      tree op1 = TREE_OPERAND (rhs, 1);
+
+      if (TREE_CODE (op1) == FIELD_DECL
+	  && DECL_VIRTUAL_P (op1))
+	{
+	  if (TREE_CODE (op0) == COMPONENT_REF
+	      && TREE_CODE (TREE_OPERAND (op0, 0)) == MEM_REF
+	      && TREE_CODE (TREE_TYPE (TREE_OPERAND (op0, 0)))== RECORD_TYPE)
+	    result = TREE_TYPE (TREE_OPERAND (op0, 0));
+	  else
+	    result = TREE_TYPE (op0);
+	}
+      else if (TREE_CODE (op0) == COMPONENT_REF)
+	{
+	  result = extract_object_class_type (op0);
+	  if (result == NULL_TREE
+	      && TREE_CODE (op1) == COMPONENT_REF)
+	    result = extract_object_class_type (op1);
+	}	  
+    }
+
+  return result;
+}
+
+bool
+vtv_defuse_fn (tree var, gimple def_stmt, void *data)
+{
+  bool retval = false;
+
+  return retval;
+}
+
+
+/* Search through all the statements in a basic block (BB), searching
+   for virtual method calls.  For each virtual method dispatch, find
+   the vptr value used, and the statically declared type of the
+   object; retrieve the vtable map variable for the type of the
+   object; generate a call to __VLTVerifyVtablePointer; and insert the
+   generated call into the basic block, after the point where the vptr
+   value is gotten out of the object and before the virtual method
+   dispatch. Make the virtual method dispatch depend on the return
+   value from the verification call, so that subsequent optimizations
+   cannot reorder the two calls.  */
+
+static void
+verify_bb_vtables (basic_block bb)
+{
+  gimple_seq stmts;
+  gimple stmt = NULL;
+  gimple_stmt_iterator gsi_vtbl_assign;
+  gimple_stmt_iterator gsi_virtual_call;
+  tree this_object;
+
+  stmts = bb_seq (bb);
+  gsi_virtual_call = gsi_start (stmts);
+  this_object = NULL_TREE;
+  for (; !gsi_end_p (gsi_virtual_call); gsi_next (&gsi_virtual_call))
+    {
+      stmt = gsi_stmt (gsi_virtual_call);
+      if (is_vtable_assignment_stmt (stmt))
+        {
+          tree lhs = gimple_assign_lhs (stmt);
+          tree vtbl_var_decl = NULL_TREE;
+          struct vtbl_map_node *vtable_map_node;
+          tree vtbl_decl = NULL_TREE;
+          gimple call_stmt;
+          struct gimplify_ctx gctx;
+          const char *vtable_name = "<unknown>";
+          tree tmp0;
+          bool found;
+
+          gsi_vtbl_assign = gsi_for_stmt (stmt);
+
+          /* Now we have found the virtual method dispatch and
+             the preceding access of the _vptr.* field... Next
+             we need to find the statically declared type of
+             the object, so we can find and use the right
+             vtable map variable in the verification call.  */
+          tree class_type = extract_object_class_type (gimple_assign_rhs1 (stmt));
+
+          if (class_type
+              && (TREE_CODE (class_type) == RECORD_TYPE)
+              && TYPE_BINFO (class_type))
+            {
+              /* Get the vtable VAR_DECL for the type.  */
+              vtbl_var_decl = BINFO_VTABLE (TYPE_BINFO (class_type));
+
+              if (TREE_CODE (vtbl_var_decl) == POINTER_PLUS_EXPR)
+                vtbl_var_decl = TREE_OPERAND (TREE_OPERAND (vtbl_var_decl, 0),
+                                              0);
+
+              gcc_assert (vtbl_var_decl);
+
+              vtbl_decl = vtbl_var_decl;
+              vtable_map_node = vtbl_map_get_node (class_type);
+
+              gcc_assert (verify_vtbl_ptr_fndecl);
+
+              /* Given the vtable pointer for the base class of the
+                 object, build the call to __VLTVerifyVtablePointer to
+                 verify that the object's vtable pointer (contained in
+                 lhs) is in the set of valid vtable pointers for the
+                 base class.  */
+
+              if (vtable_map_node && vtable_map_node->vtbl_map_decl)
+                {
+		  use_operand_p use_p;
+		  ssa_op_iter iter;
+
+                  vtable_map_node->is_used = true;
+                  vtbl_var_decl = vtable_map_node->vtbl_map_decl;
+
+                  if (TREE_CODE (vtbl_decl) == VAR_DECL)
+                    vtable_name = IDENTIFIER_POINTER (DECL_NAME (vtbl_decl));
+
+                  push_gimplify_context (&gctx);
+
+                  /* Call different routines if we are interested in
+                     trace information to debug problems.  */
+                  if (vtv_debug)
+                    {
+                      int len1 = IDENTIFIER_LENGTH
+                                                 (DECL_NAME (vtbl_var_decl));
+                      int len2 = strlen (vtable_name);
+
+                      call_stmt = gimple_build_call
+                                     (verify_vtbl_ptr_fndecl, 4,
+                                      build1 (ADDR_EXPR,
+                                                TYPE_POINTER_TO
+                                                  (TREE_TYPE (vtbl_var_decl)),
+                                              vtbl_var_decl),
+                                      lhs,
+                                      build_string_literal
+                                                  (len1 + 1,
+                                                   IDENTIFIER_POINTER
+                                                       (DECL_NAME
+                                                            (vtbl_var_decl))),
+                                      build_string_literal (len2 + 1,
+                                                            vtable_name));
+                    }
+                  else
+                    call_stmt = gimple_build_call
+                                     (verify_vtbl_ptr_fndecl, 2,
+                                      build1 (ADDR_EXPR,
+                                                TYPE_POINTER_TO
+                                                  (TREE_TYPE (vtbl_var_decl)),
+                                                 vtbl_var_decl),
+                                      lhs);
+
+
+		  /* Create a new SSA_NAME var to hold the call's
+		     return value, and make the call_stmt use the
+		     variable for that purpose.  */
+                  tmp0 = make_temp_ssa_name (TREE_TYPE (lhs), NULL, "VTV");
+                  gimple_call_set_lhs (call_stmt, tmp0);
+                  update_stmt (call_stmt);
+                  
+		  /* Find the next stmt, after the vptr assignment
+		     statememt, which should use the result of the
+		     vptr assignment statement value. */
+                  gsi_next (&gsi_vtbl_assign);
+                  gimple next_stmt = gsi_stmt (gsi_vtbl_assign);
+
+		  if (!next_stmt)
+		    {
+		      pop_gimplify_context (NULL);
+		      return;
+		    }
+
+		  /* Find any/all uses of 'lhs' in next_stmt, and
+		     replace them with 'tmp0'.  */
+		  found = false;
+		  FOR_EACH_PHI_OR_STMT_USE (use_p, next_stmt, iter,
+					    SSA_OP_ALL_USES)
+		    {
+		      tree op = USE_FROM_PTR (use_p);
+		      if (op == lhs)
+			{
+			  SET_USE (use_p, tmp0);
+			  found = true;
+			}
+		    }
+		  update_stmt (next_stmt);
+		  gcc_assert (found);
+
+                  /* Insert the new call just before the original use
+                     of the object's vtable pointer (i.e. just before
+                     'next_stmt').  */
+		  gsi_vtbl_assign = gsi_for_stmt (stmt);
+		  gsi_insert_after (&gsi_vtbl_assign, call_stmt,
+				    GSI_NEW_STMT);
+
+                  pop_gimplify_context (NULL);
+
+                  any_verification_calls_generated = true;
+                }
+            }
+        }
+    }
+}
+
+/* Main function, called from pass->excute().  Loop through all the
+   basic blocks in the current function, passing them to
+   verify_bb_vtables, which searches for virtual calls, and inserts
+   calls to __VLTVerifyVtablePointer.  */
+
+unsigned int
+vtable_verify_main (void)
+{
+  unsigned int ret = 1;
+  basic_block bb;
+
+  FOR_ALL_BB (bb)
+      verify_bb_vtables (bb);
+
+  return ret;
+}
+
+/* Gate function for the pass.  */
+
+static bool
+gate_tree_vtable_verify (void)
+{
+  return (flag_vtable_verify);
+}
+
+/* Definition of this optimization pass.  */
+
+struct gimple_opt_pass pass_vtable_verify =
+{
+ {
+  GIMPLE_PASS,
+  "vtable-verify",                      /* name */
+  OPTGROUP_NONE,                        /* optinfo_flags */
+  gate_tree_vtable_verify,              /* gate */
+  vtable_verify_main,                   /* execute */
+  NULL,                                 /* sub */
+  NULL,                                 /* next */
+  0,                                    /* static_pass_number */
+  TV_VTABLE_VERIFICATION,               /* tv_id */
+  PROP_cfg | PROP_ssa,                  /* properties_required */
+  0,                                    /* properties_provided */
+  0,                                    /* properties_destroyed */
+  0,                                    /* todo_flags_start */
+  TODO_update_ssa
+    | TODO_ggc_collect                  /* todo_flags_finish */
+ }
+};
+
+#include "gt-tree-vtable-verify.h"
Index: gcc/tree-vtable-verify.h
===================================================================
--- gcc/tree-vtable-verify.h	(revision 0)
+++ gcc/tree-vtable-verify.h	(revision 0)
@@ -0,0 +1,138 @@
+/* Interprocedural constant propagation
+   Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011
+   Free Software Foundation, Inc.
+
+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/>.  */
+
+/* Virtual Table Pointer Security.  */
+
+#ifndef TREE_VTABLE_VERIFY_H
+#define TREE_VTABLE_VERIFY_H
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "timevar.h"
+#include "cpplib.h"
+#include "tree.h"
+#include "hashtab.h"
+#include "sbitmap.h"
+
+/* The function decl used to create calls to __VLTVtableVerify.  It must
+   be global because it needs to be initialized in the C++ front end, but
+   used in the middle end (in the vtable verification pass).  */
+
+extern tree verify_vtbl_ptr_fndecl;
+
+/* Global variable keeping track of how many vtable map variables we
+   have created. */
+extern unsigned num_vtable_map_nodes;
+
+/* Global variable that records whether or not any vtable verification
+   calls have been generated.  */
+extern bool any_verification_calls_generated;
+
+/* Each vtable map variable corresponds to a virtual class.  Each
+   vtable map variable has a hash table associated with it, that keeps
+   track of the vtable pointers for which we have generated a call to
+   __VLTRegisterPair (with the current vtable map variable).  This is
+   the hash table node that is used for each entry in this hash table
+   of vtable pointers.
+
+   Sometimes there are multiple valid vtable pointer entries that use
+   the same vtable pointer decl with different offsets.  Therefore,
+   for each vtable pointer in the hash table, there is also an array
+   of offsets used with that vtable. */
+
+struct vtable_registration
+{
+  tree vtable_decl;            /* The var decl of the vtable.               */
+  vec<unsigned> offsets;       /* The offsets array.                        */
+};
+
+/*  This struct is used to represent the class hierarchy information
+    that we need.  Each vtable map variable has an associated class
+    hierarchy node (struct vtv_graph_node).  Note: In this struct,
+    'children' means immediate descendants in the class hierarchy;
+    'descendant' means any descendant however many levels deep. */
+
+struct vtv_graph_node {
+  tree class_type;                  /* The record_type of the class.        */
+  unsigned class_uid;               /* A unique, monotonically
+                                       ascending id for class node.
+                                       Each vtable map node also has
+                                       an id.  The class uid is the
+                                       same as the vtable map node id
+                                       for nodes corresponding to the
+                                       same class.                          */
+  unsigned num_processed_children;  /* # of children for whom we have
+                                       computed the class hierarchy
+                                       transitive closure.                  */
+  vec<struct vtv_graph_node *> parents;  /* Vector of parents in the graph. */
+  vec<struct vtv_graph_node *> children; /* Vector of children in the graph.*/
+  sbitmap descendants;              /* Bitmap representing all this node's
+                                       descendants in the graph.            */
+};
+
+/* This is the node used for our hashtable of vtable map variable
+   information.  When we create a vtable map variable (var decl) we
+   put it into one of these nodes; create a corresponding
+   vtv_graph_node for our class hierarchy info and store that in this
+   node; generate a unique (monotonically ascending) id for both the
+   vtbl_map_node and the vtv_graph_node; and insert the node into two
+   data structures (to make it easy to find in several different
+   ways): 1). A hash table ("vtbl_map_hash" in tree-vtable-verify.c).
+   This gives us an easy way to check to see if we already have a node
+   for the vtable map variable or not; and 2). An array (vector) of
+   vtbl_map_nodes, where the array index corresponds to the unique id
+   of the vtbl_map_node, which gives us an easy way to use bitmaps to
+   represent and find the vtable map nodes.  */
+
+struct vtbl_map_node {
+  tree vtbl_map_decl;                 /* The var decl for the vtable map
+                                         variable.                          */
+  tree class_name;                    /* The DECL_ASSEMBLER_NAME of the
+                                         class.                             */
+  struct vtv_graph_node *class_info;  /* Our class hierarchy info for the
+                                         class.                             */
+  unsigned uid;                       /* The unique id for the vtable map
+                                         variable.                          */
+  struct vtbl_map_node *next, *prev;  /* Pointers for the linked list
+                                         structure.                         */
+  htab_t registered;     /* Hashtable of vtable pointers for which we have
+                            generated a _VLTRegisterPair call with this vtable
+                            map variable.                                   */
+  bool is_used;          /* Boolean indicating if we used this vtable map
+                            variable in a call to __VLTVerifyVtablePointer. */
+};
+
+/* Controls debugging for vtable verification.  */
+extern bool vtv_debug;
+
+/* The global vector of vtbl_map_nodes.  */
+extern vec<struct vtbl_map_node *> vtbl_map_nodes_vec;
+
+extern struct vtbl_map_node *vtbl_map_get_node (tree);
+extern struct vtbl_map_node *find_or_create_vtbl_map_node (tree);
+extern void vtbl_map_node_class_insert (struct vtbl_map_node *, unsigned);
+extern bool vtbl_map_node_registration_find (struct vtbl_map_node *,
+                                             tree, unsigned);
+extern bool vtbl_map_node_registration_insert (struct vtbl_map_node *,
+                                               tree, unsigned);
+
+#endif /* TREE_VTABLE_VERIFY_H */
Index: gcc/common.opt
===================================================================
--- gcc/common.opt	(revision 196266)
+++ gcc/common.opt	(working copy)
@@ -2270,6 +2270,22 @@ Enum(symbol_visibility) String(hidden) V
 EnumValue
 Enum(symbol_visibility) String(protected) Value(VISIBILITY_PROTECTED)
 
+fvtable-verify=
+Common Joined RejectNegative Enum(vtv_priority) Var(flag_vtable_verify) Init(VTV_NO_PRIORITY)
+Validate vtable pointers before using them.
+
+Enum
+Name(vtv_priority) Type(enum vtv_priority) UnknownError(unknown vtable verify initialization priority %qs)
+
+EnumValue
+Enum(vtv_priority) String(none) Value(VTV_NO_PRIORITY)
+
+EnumValue
+Enum(vtv_priority) String(std) Value(VTV_STANDARD_PRIORITY)
+
+EnumValue
+Enum(vtv_priority) String(preinit) Value(VTV_PREINIT_PRIORITY)
+
 fvpt
 Common Report Var(flag_value_profile_transformations) Optimization
 Use expression value profiles in optimizations
Index: gcc/timevar.def
===================================================================
--- gcc/timevar.def	(revision 196266)
+++ gcc/timevar.def	(working copy)
@@ -255,6 +255,7 @@ DEFTIMEVAR (TV_TREE_UNINIT           , "
 DEFTIMEVAR (TV_PLUGIN_INIT           , "plugin initialization")
 DEFTIMEVAR (TV_PLUGIN_RUN            , "plugin execution")
 DEFTIMEVAR (TV_GIMPLE_SLSR           , "straight-line strength reduction")
+DEFTIMEVAR (TV_VTABLE_VERIFICATION   , "vtable verification")
 
 /* Everything else in rest_of_compilation not included above.  */
 DEFTIMEVAR (TV_EARLY_LOCAL	     , "early local passes")
Index: gcc/config/gnu-user.h
===================================================================
--- gcc/config/gnu-user.h	(revision 196266)
+++ gcc/config/gnu-user.h	(working copy)
@@ -43,11 +43,13 @@ see the files COPYING3 and COPYING.RUNTI
 #if defined HAVE_LD_PIE
 #define GNU_USER_TARGET_STARTFILE_SPEC \
   "%{!shared: %{pg|p|profile:gcrt1.o%s;pie:Scrt1.o%s;:crt1.o%s}} \
-   crti.o%s %{static:crtbeginT.o%s;shared|pie:crtbeginS.o%s;:crtbegin.o%s}"
+   crti.o%s %{static:crtbeginT.o%s;shared|pie:crtbeginS.o%s;:crtbegin.o%s} \
+   %{fvtable-verify*:vtv_start.o%s}"
 #else
 #define GNU_USER_TARGET_STARTFILE_SPEC \
   "%{!shared: %{pg|p|profile:gcrt1.o%s;:crt1.o%s}} \
-   crti.o%s %{static:crtbeginT.o%s;shared|pie:crtbeginS.o%s;:crtbegin.o%s}"
+   crti.o%s %{static:crtbeginT.o%s;shared|pie:crtbeginS.o%s;:crtbegin.o%s} \
+   %{fvtable-verify*:vtv_start.o%s}"
 #endif
 #undef  STARTFILE_SPEC
 #define STARTFILE_SPEC GNU_USER_TARGET_STARTFILE_SPEC
@@ -59,7 +61,8 @@ see the files COPYING3 and COPYING.RUNTI
    GNU userspace "finalizer" file, `crtn.o'.  */
 
 #define GNU_USER_TARGET_ENDFILE_SPEC \
-  "%{shared|pie:crtendS.o%s;:crtend.o%s} crtn.o%s"
+  "%{fvtable-verify*:vtv_end.o%s} \
+   %{shared|pie:crtendS.o%s;:crtend.o%s} crtn.o%s"
 #undef  ENDFILE_SPEC
 #define ENDFILE_SPEC GNU_USER_TARGET_ENDFILE_SPEC
 
Index: gcc/tree.h
===================================================================
--- gcc/tree.h	(revision 196266)
+++ gcc/tree.h	(working copy)
@@ -6449,6 +6449,9 @@ is_lang_specific (tree t)
 /* In gimple-low.c.  */
 extern bool block_may_fallthru (const_tree);
 
+/* In tree-vtable-verify.c.  */
+extern void save_vtable_map_decl (tree);
+
 \f
 /* Functional interface to the builtin functions.  */
 
@@ -6539,4 +6542,5 @@ builtin_decl_implicit_p (enum built_in_f
 	  && builtin_info.implicit_p[uns_fncode]);
 }
 
+
 #endif  /* GCC_TREE_H  */
Index: gcc/vtv_end.c
===================================================================
--- gcc/vtv_end.c	(revision 0)
+++ gcc/vtv_end.c	(revision 0)
@@ -0,0 +1,60 @@
+/*  Copyright (C) 2012, 2013
+    Free Software Foundation, Inc.
+
+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/>.  */
+
+/* This file is part of the vtable verification feature (for a
+   detailed description of the feature, see comments in
+   tree-vtable-verify.c).  The vtable verification feature creates
+   certain global symbols that need to be read-write sometimes during
+   program execution, and read-only at others.  It uses 'mprotect' to
+   change the memory protections of the pages on which these variables
+   are stored.  In order to not affect the protections of other
+   program variables, these variables are put into a special named
+   section, ".vtable_map_vars", which is page-aligned at the start,
+   and which is padded with a page-sized amount of zeros at the end.
+   To make this section page aligned, we create a special symbol,
+   "_vtable_map_vars_start" which we make the very first thing that
+   goes into the section.  That is defined in vtv_start.c (which
+   contains nothing else).  vtv_start.c gest compiled into
+   vtv_start.o, and vtv_start.o gets inserted into the link line
+   immediately after crtbegin.o, if the program is compiled with
+   -fvtable.verify.
+
+   In order to pad the ".vtable_map_vars" section with a page-sized
+   amount of zeros at the end, there is a second symbol,
+   _vtable_map_vars_end.  This file defines that symbol (and only this
+   symbol).  This second symbol is a page-sized array of chars,
+   zero-filled, and is the very last thing to go into the section.
+   When the GCC driver inserts vtv_start.o into the link line (just
+   after crtbegin.o) it also inserts vtv_end.o into the link line,
+   just before crtend.o.  This has the desired effect of making our
+   section page-aligned and page-size paded, ensuring that no other
+   program data lands on our pages.  */
+
+
+#define PAGE_SIZE 4096
+
+#ifdef BIG_PAGE_SIZE
+/* TODO - Replace '4096' below with correct big page size.  */
+#define PAGE_SIZE 4096
+#endif
+
+/* Page-sized variable to mark end of .vtable_map_vars section.  */
+char _vtable_map_vars_end[PAGE_SIZE]
+  __attribute__ ((__visibility__ ("protected"), used,
+		  section(".vtable_map_vars")));
Index: gcc/flag-types.h
===================================================================
--- gcc/flag-types.h	(revision 196266)
+++ gcc/flag-types.h	(working copy)
@@ -191,4 +191,10 @@ enum fp_contract_mode {
   FP_CONTRACT_FAST = 2
 };
 
+/* flag_vtable_verify initialization levels. */
+enum vtv_priority {
+  VTV_NO_PRIORITY       = 0,  /* i.E. Do NOT do vtable verification. */
+  VTV_STANDARD_PRIORITY = 1,
+  VTV_PREINIT_PRIORITY  = 2
+};
 #endif /* ! GCC_FLAG_TYPES_H */
Index: gcc/Makefile.in
===================================================================
--- gcc/Makefile.in	(revision 196266)
+++ gcc/Makefile.in	(working copy)
@@ -1444,6 +1444,7 @@ OBJS = \
 	tree-vect-loop-manip.o \
 	tree-vect-slp.o \
 	tree-vectorizer.o \
+	tree-vtable-verify.o \
 	tree-vrp.o \
 	tree.o \
 	valtrack.o \
@@ -2612,6 +2613,12 @@ tree-vectorizer.o: tree-vectorizer.c $(C
    dumpfile.h $(TM_H) $(GGC_H) $(TREE_H) $(TREE_FLOW_H) \
    $(CFGLOOP_H) $(TREE_PASS_H) $(TREE_VECTORIZER_H) \
    $(TREE_PRETTY_PRINT_H)
+tree-vtable-verify.o: tree-vtable-verify.c tree-vtable-verify.h $(CONFIG_H) \
+   $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) cp/cp-tree.h $(TM_P_H) \
+   $(BASIC_BLOCK_H) output.h $(TREE_FLOW_H) $(TREE_DUMP_H) $(TREE_PASS_H) \
+   $(TIMEVAR_H) $(CFGLOOP_H) $(FLAGS_H)  $(TREE_INLINE_H) $(SCEV_H) \
+   $(DIAGNOSTIC_CORE_H) $(GIMPLE_PRETTY_PRINT_H) toplev.h langhooks.h \
+   gt-tree-vtable-verify.h
 tree-loop-distribution.o: tree-loop-distribution.c $(CONFIG_H) $(SYSTEM_H) \
    coretypes.h $(TREE_FLOW_H) $(CFGLOOP_H) $(TREE_DATA_REF_H) $(TREE_PASS_H)
 tree-parloops.o: tree-parloops.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
@@ -3751,6 +3758,7 @@ GTFILES = $(CPP_ID_DATA_H) $(srcdir)/inp
   $(srcdir)/lto-streamer.h \
   $(srcdir)/target-globals.h \
   $(srcdir)/ipa-inline.h \
+  $(srcdir)/tree-vtable-verify.c \
   $(srcdir)/asan.c \
   $(srcdir)/tsan.c \
   @all_gtfiles@
Index: gcc/varasm.c
===================================================================
--- gcc/varasm.c	(revision 196266)
+++ gcc/varasm.c	(working copy)
@@ -2033,7 +2033,21 @@ assemble_variable (tree decl, int top_le
     assemble_noswitch_variable (decl, name, sect);
   else
     {
-      switch_to_section (sect);
+      if (sect->named.name
+	  && (strcmp (sect->named.name, ".vtable_map_vars") == 0))
+	{
+#if defined (OBJECT_FORMAT_ELF)
+          targetm.asm_out.named_section (sect->named.name,
+					 sect->named.common.flags
+				         | SECTION_LINKONCE,
+			    	         DECL_NAME (decl));
+          in_section = sect;
+#else
+          switch_to_section (sect);
+#endif
+        }
+      else
+        switch_to_section (sect);
       if (DECL_ALIGN (decl) > BITS_PER_UNIT)
 	ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (DECL_ALIGN_UNIT (decl)));
       assemble_variable_contents (decl, name, dont_output_data);
@@ -2046,6 +2060,23 @@ assemble_variable (tree decl, int top_le
     }
 }
 
+
+/* Given a function declaration (FN_DECL), this function assembles the
+   function into the .preinit_array section.  */
+
+void
+assemble_vtv_preinit_initializer (tree fn_decl)
+{
+  section *sect;
+  unsigned flags = SECTION_WRITE;
+  rtx symbol = XEXP (DECL_RTL (fn_decl), 0);
+
+  flags |= SECTION_NOTYPE;
+  sect = get_section (".preinit_array", flags, fn_decl);
+  switch_to_section (sect);
+  assemble_addr_to_section (symbol, sect);
+}
+
 /* Return 1 if type TYPE contains any pointers.  */
 
 static int
@@ -6007,6 +6038,9 @@ default_section_type_flags (tree decl, c
   if (decl && DECL_ONE_ONLY (decl))
     flags |= SECTION_LINKONCE;
 
+  if (strcmp (name, ".vtable_map_vars") == 0)
+      flags |= SECTION_LINKONCE;
+
   if (decl && TREE_CODE (decl) == VAR_DECL && DECL_THREAD_LOCAL_P (decl))
     flags |= SECTION_TLS | SECTION_WRITE;
 
Index: gcc/output.h
===================================================================
--- gcc/output.h	(revision 196266)
+++ gcc/output.h	(working copy)
@@ -197,6 +197,10 @@ extern void assemble_end_function (tree,
    initial value (that will be done by the caller).  */
 extern void assemble_variable (tree, int, int, int);
 
+/* Put the vtable verification constructor initialization function
+   into the preinit array.  */
+extern void assemble_vtv_preinit_initializer (tree);
+
 /* Compute the alignment of variable specified by DECL.
    DONT_OUTPUT_DATA is from assemble_variable.  */
 extern void align_variable (tree decl, bool dont_output_data);

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH, updated] Vtable pointer verification, main gcc changes (patch 2 of 3)
  2013-02-25 19:28 [PATCH, updated] Vtable pointer verification, main gcc changes (patch 2 of 3) Caroline Tice
@ 2013-03-07 23:55 ` Caroline Tice
  2013-03-13 17:48 ` Diego Novillo
  1 sibling, 0 replies; 4+ messages in thread
From: Caroline Tice @ 2013-03-07 23:55 UTC (permalink / raw)
  To: GCC Patches
  Cc: Diego Novillo, Luis Lozano, Bhaskar Janakiraman, Caroline Tice

Ping?

-- Caroline
cmtice@google.com


On Mon, Feb 25, 2013 at 11:27 AM, Caroline Tice <cmtice@google.com> wrote:
> Here are the latest changes to the vtable pointer verification patches
> (again there are 3 patches: c++ front end, main gcc, and c++ runtime
> library).  I think these address all the review comments I have
> received so far.  This patch is the for main gcc.  Please review these
> changes and let me know if they will be ok to commit once stage 1
> opens.
>
> -- Caroline Tice
> cmtice@google.com
>
> 2013-02-25  Caroline Tice  <cmtice@google.com>
>
>         * configure (CXX_FOR_TARGET): Add libstdc++-v3/libsupc++/.libs to the
>         library search path.
>         * ligbcc/config.host (extra_parts):  Add vtv_start.o and vtv_end.o to
>         the list.
>         * libgcc/Makefile.in: Add definitin for gcc_srcdir; add rules for
>         building vtv_start.o and vtv_end.o.
>         * passes.c (init_optimization_pass): Add pass_vtable_verify.
>         * vtv_start.c:  New file.
>         * tree-pass.h (pass_vtable_verify): Declare new pass.
>         * tree-vtable-verify.c:  New file, contains vtable verification tree
>         pass.
>         * tree-vtable-verify.h: New file.
>         * common.opt: (fvtable-verify=): New option. Also define vtv_priority
>         values for the option.
>         * timevar.def (TV_VTABLE_VERIFICATION):  Declare new time var.
>         * config/gnu-user.h: Add vtv_start.o to STARTFILE_SPEC if
>         fvtable-verify is present; Add vtv_end.o to ENDFILE_SPEC if
>         fvtable-verify is present.
>         * tree.h: Add extern function declaration for save_vtable_map_decl.
>         * vtv_end.c:  New file.
>         * flag-types.h (vtv_priority):  New enum, for values for new
>         '-fvtable-verify=' option.
>         * Makefile.in (OBJS):  Add tree-vtable-verify.o to list of object
>         files.
>         (tree-vtable-verify.o):  Add rule for building object file.
>         (GTFILES): Add tree-vtable-verify.c to list of files that use GCC's
>         garbage collector.
>         * varasm.c (assemble_variable): Add code for handling variables that
>         go into the ".vtable_map_vars" section.
>         (assemble_vtv_perinit_initializer):  New function.
>         (default_section_type_flags):  Add SECTION_LINKONCE to
>         ".vtable_map_vars" section items.
>         * output.h (assemble_vtv_preinit_initializer):  External function decl.

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH, updated] Vtable pointer verification, main gcc changes (patch 2 of 3)
  2013-02-25 19:28 [PATCH, updated] Vtable pointer verification, main gcc changes (patch 2 of 3) Caroline Tice
  2013-03-07 23:55 ` Caroline Tice
@ 2013-03-13 17:48 ` Diego Novillo
  2013-05-24 20:52   ` Caroline Tice
  1 sibling, 1 reply; 4+ messages in thread
From: Diego Novillo @ 2013-03-13 17:48 UTC (permalink / raw)
  To: Caroline Tice; +Cc: GCC Patches, Luis Lozano, Bhaskar Janakiraman

On 2013-02-25 14:27 , Caroline Tice wrote:

> Index: libgcc/Makefile.in
> ===================================================================
> --- libgcc/Makefile.in    (revision 196266)
> +++ libgcc/Makefile.in    (working copy)
> @@ -22,6 +22,7 @@
>  libgcc_topdir = @libgcc_topdir@
>  host_subdir = @host_subdir@
>
> +gcc_srcdir = $(libgcc_topdir)/gcc
>  gcc_objdir = $(MULTIBUILDTOP)../../$(host_subdir)/gcc
>
>  srcdir = @srcdir@
> @@ -969,6 +970,16 @@ crtendS$(objext): $(srcdir)/crtstuff.c
>  # This is a version of crtbegin for -static links.
>  crtbeginT$(objext): $(srcdir)/crtstuff.c
>      $(crt_compile) $(CRTSTUFF_T_CFLAGS) -c $< -DCRT_BEGIN -DCRTSTUFFT_O
> +
> +# These are used in vtable verification; see comments in source files for
> +# more details.
> +vtv_start$(objext): $(gcc_srcdir)/vtv_start.c
> +    $(crt_compile) $(CRTSTUFF_T_CFLAGS_S) \
> +      -c $(gcc_srcdir)/vtv_start.c
> +
> +vtv_end$(objext): $(gcc_srcdir)/vtv_end.c
> +    $(crt_compile) $(CRTSTUFF_T_CFLAGS_S) \
> +      -c $(gcc_srcdir)/vtv_end.c
>  endif

Why not have these two files in libgcc?  I don't think we want to depend 
on source files in gcc/ from libgcc/

>
>
>  /* IPA Passes */
>  extern struct simple_ipa_opt_pass pass_ipa_lower_emutls;
> Index: gcc/tree-vtable-verify.c
> ===================================================================
> --- gcc/tree-vtable-verify.c    (revision 0)
> +++ gcc/tree-vtable-verify.c    (revision 0)
I would like to get rid of this naming convention where we prefix file 
names with 'tree-'.  Just vtable-verify.c is fine.

> @@ -0,0 +1,724 @@
> +/*   Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011
Copyright (C) 2013

>
> +/* Virtual Table Pointer Security Pass - Detect corruption of vtable 
> pointers
> +   before using them for virtual method dispatches.  */

Do you have a URL to a paper/presentation for it?

> +
> +  To find and reference the set of valid vtable pointers for any given
> +  virtual class, we create a special global varible for each virtual
s/varible/variable/

>
> +
> +  Some implementation details for this pass:
> +
> +  To find the all of the virtual calls, we iterate through all the
s/the all/all/
>
> +  struct vtable_registration key;
> +  struct vtable_registration **slot;
> +
> +  gcc_assert (node && node->registered);
> +
> +  key.vtable_decl = vtable_decl;
> +  slot = (struct vtable_registration **) htab_find_slot 
> (node->registered,
> + &key, NO_INSERT);
Unless you need to use this in an old branch, I strongly suggest using 
the new hash table facilities (hash-table.h).

> +
> +
> +/* Here are the three two structures into which we insert vtable map 
> nodes.
'three two'?
>
> +  /* Verify that there aren't any qualifiers on the type.  */
> +  type_quals = TYPE_QUALS (TREE_TYPE (class_type_decl));
> +  gcc_assert (type_quals == TYPE_UNQUALIFIED);
> +
> +  /* Get the mangled name for the unqualified type.  */
> +  class_name = DECL_ASSEMBLER_NAME (class_type_decl);

DECL_ASSEMBLER_NAME has side-effects (it generates one if there isn't 
one already).  Just to avoid this unwanted side effect, protect it with 
if (HAS_DECL_ASSEMBLER_NAME_P).  In fact, I think you should abort if 
the class_type_decl does *not* have one.  So, just adding gcc_assert 
(HAS_DECL_ASSEMBLER_NAME_P(class_type_decl)) should be sufficient.

>
> +
> +/* This function attempts to recover the declared class of an object
> +   that is used in making a virtual call.  We try to get the type from
> +   the type cast in the gimple assignment statement that extracts the
> +   vtable pointer from the object (DEF_STMT).  The gimple statment
s/statment/statement/
> +   usually looks something like this:
> +
> +   D.2201_4 = MEM[(struct Event *)this_1(D)]._vptr.Event    */
> +
> +static tree
> +/* extract_object_class_type (gimple def_stmt) */
Remove this?
> +extract_object_class_type (tree rhs)
> +{
> +  /* tree rhs = NULL_TREE; */
> +
> +  /* Try to find and extract the type cast from that stmt.  */
> +
> +  /* rhs = gimple_assign_rhs1 (def_stmt); */
> +  /*
> +  if (TREE_CODE (rhs) == COMPONENT_REF)
> +    {
> +      while (TREE_CODE (rhs) == COMPONENT_REF
> +             && (TREE_CODE (TREE_OPERAND (rhs, 0)) == COMPONENT_REF))
> +        rhs = TREE_OPERAND (rhs, 0);
> +
> +      if (TREE_CODE (rhs) == COMPONENT_REF
> +          && TREE_CODE (TREE_OPERAND (rhs, 0)) == MEM_REF
> +          && TREE_CODE (TREE_TYPE (TREE_OPERAND (rhs, 0)))== RECORD_TYPE)
> +        rhs = TREE_TYPE (TREE_OPERAND (rhs, 0));
> +      else
> +        rhs = NULL_TREE;
> +    }
> +  else
> +    rhs = NULL_TREE;
> +  */

What's this?  Is it needed?  There's some other commented code here that 
seems out of place.

> +
> +  tree result = NULL_TREE;
> +
> +
> +  if (TREE_CODE (rhs) == COMPONENT_REF)
> +    {
> +      tree op0 = TREE_OPERAND (rhs, 0);
> +      tree op1 = TREE_OPERAND (rhs, 1);
> +
> +      if (TREE_CODE (op1) == FIELD_DECL
> +      && DECL_VIRTUAL_P (op1))
> +    {
> +      if (TREE_CODE (op0) == COMPONENT_REF
> +          && TREE_CODE (TREE_OPERAND (op0, 0)) == MEM_REF
> +          && TREE_CODE (TREE_TYPE (TREE_OPERAND (op0, 0)))== RECORD_TYPE)
> +        result = TREE_TYPE (TREE_OPERAND (op0, 0));
> +      else
> +        result = TREE_TYPE (op0);
> +    }
> +      else if (TREE_CODE (op0) == COMPONENT_REF)
> +    {
> +      result = extract_object_class_type (op0);
> +      if (result == NULL_TREE
> +          && TREE_CODE (op1) == COMPONENT_REF)
> +        result = extract_object_class_type (op1);
> +    }
> +    }
Indentation seems off here.
> +
> +  return result;
> +}
> +
> +bool
> +vtv_defuse_fn (tree var, gimple def_stmt, void *data)
> +{
> +  bool retval = false;
> +
> +  return retval;
> +}

Huh?

>
> +  for (; !gsi_end_p (gsi_virtual_call); gsi_next (&gsi_virtual_call))
> +    {
> +      stmt = gsi_stmt (gsi_virtual_call);
> +      if (is_vtable_assignment_stmt (stmt))
> +        {
> +          tree lhs = gimple_assign_lhs (stmt);
> +          tree vtbl_var_decl = NULL_TREE;
> +          struct vtbl_map_node *vtable_map_node;
> +          tree vtbl_decl = NULL_TREE;
> +          gimple call_stmt;
> +          struct gimplify_ctx gctx;
> +          const char *vtable_name = "<unknown>";
> +          tree tmp0;
> +          bool found;
> +
> +          gsi_vtbl_assign = gsi_for_stmt (stmt);
Why not use 'gsi_virtual_call'?

>
> +                  if (TREE_CODE (vtbl_decl) == VAR_DECL)
> +                    vtable_name = IDENTIFIER_POINTER (DECL_NAME 
> (vtbl_decl));
> +
> +                  push_gimplify_context (&gctx);
Not needed.  You are not calling the gimplifier.

>
> +
> +          if (!next_stmt)
> +            {
> +              pop_gimplify_context (NULL);
Likewise.

>
> +          gsi_insert_after (&gsi_vtbl_assign, call_stmt,
> +                    GSI_NEW_STMT);
> +
> +                  pop_gimplify_context (NULL);
Likewise.


Diego.

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH, updated] Vtable pointer verification, main gcc changes (patch 2 of 3)
  2013-03-13 17:48 ` Diego Novillo
@ 2013-05-24 20:52   ` Caroline Tice
  0 siblings, 0 replies; 4+ messages in thread
From: Caroline Tice @ 2013-05-24 20:52 UTC (permalink / raw)
  To: Diego Novillo; +Cc: GCC Patches, Luis Lozano, Bhaskar Janakiraman

On Wed, Mar 13, 2013 at 10:48 AM, Diego Novillo <dnovillo@google.com> wrote:
>
> On 2013-02-25 14:27 , Caroline Tice wrote:
>
>> Index: libgcc/Makefile.in
>> ===================================================================
>> --- libgcc/Makefile.in    (revision 196266)
>> +++ libgcc/Makefile.in    (working copy)
>> @@ -22,6 +22,7 @@
>>  libgcc_topdir = @libgcc_topdir@
>>  host_subdir = @host_subdir@
>>
>> +gcc_srcdir = $(libgcc_topdir)/gcc
>>  gcc_objdir = $(MULTIBUILDTOP)../../$(host_subdir)/gcc
>>
>>  srcdir = @srcdir@
>> @@ -969,6 +970,16 @@ crtendS$(objext): $(srcdir)/crtstuff.c
>>  # This is a version of crtbegin for -static links.
>>  crtbeginT$(objext): $(srcdir)/crtstuff.c
>>      $(crt_compile) $(CRTSTUFF_T_CFLAGS) -c $< -DCRT_BEGIN -DCRTSTUFFT_O
>> +
>> +# These are used in vtable verification; see comments in source files for
>> +# more details.
>> +vtv_start$(objext): $(gcc_srcdir)/vtv_start.c
>> +    $(crt_compile) $(CRTSTUFF_T_CFLAGS_S) \
>> +      -c $(gcc_srcdir)/vtv_start.c
>> +
>> +vtv_end$(objext): $(gcc_srcdir)/vtv_end.c
>> +    $(crt_compile) $(CRTSTUFF_T_CFLAGS_S) \
>> +      -c $(gcc_srcdir)/vtv_end.c
>>  endif
>
>
> Why not have these two files in libgcc?  I don't think we want to depend on source files in gcc/ from libgcc/
>

I will put them there.

>>
>>
>>  /* IPA Passes */
>>  extern struct simple_ipa_opt_pass pass_ipa_lower_emutls;
>> Index: gcc/tree-vtable-verify.c
>> ===================================================================
>> --- gcc/tree-vtable-verify.c    (revision 0)
>> +++ gcc/tree-vtable-verify.c    (revision 0)
>
> I would like to get rid of this naming convention where we prefix file names with 'tree-'.  Just vtable-verify.c is fine.
>
>> @@ -0,0 +1,724 @@
>> +/*   Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011
>
> Copyright (C) 2013
>
>>
>> +/* Virtual Table Pointer Security Pass - Detect corruption of vtable pointers
>> +   before using them for virtual method dispatches.  */
>
>
> Do you have a URL to a paper/presentation for it?

No, I don't at this time.

>
>> +
>> +  To find and reference the set of valid vtable pointers for any given
>> +  virtual class, we create a special global varible for each virtual
>
> s/varible/variable/
>
>>
>> +
>> +  Some implementation details for this pass:
>> +
>> +  To find the all of the virtual calls, we iterate through all the
>
> s/the all/all/
>>
>>
>> +  struct vtable_registration key;
>> +  struct vtable_registration **slot;
>> +
>> +  gcc_assert (node && node->registered);
>> +
>> +  key.vtable_decl = vtable_decl;
>> +  slot = (struct vtable_registration **) htab_find_slot (node->registered,
>> + &key, NO_INSERT);
>
> Unless you need to use this in an old branch, I strongly suggest using the new hash table facilities (hash-table.h).
>

Ok, will do.

>> +
>> +
>> +/* Here are the three two structures into which we insert vtable map nodes.
>
> 'three two'?
>>
>>
>> +  /* Verify that there aren't any qualifiers on the type.  */
>> +  type_quals = TYPE_QUALS (TREE_TYPE (class_type_decl));
>> +  gcc_assert (type_quals == TYPE_UNQUALIFIED);
>> +
>> +  /* Get the mangled name for the unqualified type.  */
>> +  class_name = DECL_ASSEMBLER_NAME (class_type_decl);
>
>
> DECL_ASSEMBLER_NAME has side-effects (it generates one if there isn't one already).  Just to avoid this unwanted side effect, protect it with if (HAS_DECL_ASSEMBLER_NAME_P).  In fact, I think you should abort if the class_type_decl does *not* have one.  So, just adding gcc_assert (HAS_DECL_ASSEMBLER_NAME_P(class_type_decl)) should be sufficient.
>

Will do.

>>
>> +
>> +/* This function attempts to recover the declared class of an object
>> +   that is used in making a virtual call.  We try to get the type from
>> +   the type cast in the gimple assignment statement that extracts the
>> +   vtable pointer from the object (DEF_STMT).  The gimple statment
>
> s/statment/statement/
>>
>> +   usually looks something like this:
>> +
>> +   D.2201_4 = MEM[(struct Event *)this_1(D)]._vptr.Event    */
>> +
>> +static tree
>> +/* extract_object_class_type (gimple def_stmt) */
>
> Remove this?

Yes (I didn't realize I had left the commented out code in the patch;
I'm sorry about that).

>>
>> +extract_object_class_type (tree rhs)
>> +{
>> +  /* tree rhs = NULL_TREE; */
>> +
>> +  /* Try to find and extract the type cast from that stmt.  */
>> +
>> +  /* rhs = gimple_assign_rhs1 (def_stmt); */
>> +  /*
>> +  if (TREE_CODE (rhs) == COMPONENT_REF)
>> +    {
>> +      while (TREE_CODE (rhs) == COMPONENT_REF
>> +             && (TREE_CODE (TREE_OPERAND (rhs, 0)) == COMPONENT_REF))
>> +        rhs = TREE_OPERAND (rhs, 0);
>> +
>> +      if (TREE_CODE (rhs) == COMPONENT_REF
>> +          && TREE_CODE (TREE_OPERAND (rhs, 0)) == MEM_REF
>> +          && TREE_CODE (TREE_TYPE (TREE_OPERAND (rhs, 0)))== RECORD_TYPE)
>> +        rhs = TREE_TYPE (TREE_OPERAND (rhs, 0));
>> +      else
>> +        rhs = NULL_TREE;
>> +    }
>> +  else
>> +    rhs = NULL_TREE;
>> +  */
>
>
> What's this?  Is it needed?  There's some other commented code here that seems out of place.
>

I will remove it.  I didn't mean for it to be in the patch.

>> +
>> +  tree result = NULL_TREE;
>> +
>> +
>> +  if (TREE_CODE (rhs) == COMPONENT_REF)
>> +    {
>> +      tree op0 = TREE_OPERAND (rhs, 0);
>> +      tree op1 = TREE_OPERAND (rhs, 1);
>> +
>> +      if (TREE_CODE (op1) == FIELD_DECL
>> +      && DECL_VIRTUAL_P (op1))
>> +    {
>> +      if (TREE_CODE (op0) == COMPONENT_REF
>> +          && TREE_CODE (TREE_OPERAND (op0, 0)) == MEM_REF
>> +          && TREE_CODE (TREE_TYPE (TREE_OPERAND (op0, 0)))== RECORD_TYPE)
>> +        result = TREE_TYPE (TREE_OPERAND (op0, 0));
>> +      else
>> +        result = TREE_TYPE (op0);
>> +    }
>> +      else if (TREE_CODE (op0) == COMPONENT_REF)
>> +    {
>> +      result = extract_object_class_type (op0);
>> +      if (result == NULL_TREE
>> +          && TREE_CODE (op1) == COMPONENT_REF)
>> +        result = extract_object_class_type (op1);
>> +    }
>> +    }
>
> Indentation seems off here.
>>
>> +
>> +  return result;
>> +}
>> +
>> +bool
>> +vtv_defuse_fn (tree var, gimple def_stmt, void *data)
>> +{
>> +  bool retval = false;
>> +
>> +  return retval;
>> +}
>
>
> Huh?
>

Another piece I meant to remove previously (sorry again).

>>
>> +  for (; !gsi_end_p (gsi_virtual_call); gsi_next (&gsi_virtual_call))
>> +    {
>> +      stmt = gsi_stmt (gsi_virtual_call);
>> +      if (is_vtable_assignment_stmt (stmt))
>> +        {
>> +          tree lhs = gimple_assign_lhs (stmt);
>> +          tree vtbl_var_decl = NULL_TREE;
>> +          struct vtbl_map_node *vtable_map_node;
>> +          tree vtbl_decl = NULL_TREE;
>> +          gimple call_stmt;
>> +          struct gimplify_ctx gctx;
>> +          const char *vtable_name = "<unknown>";
>> +          tree tmp0;
>> +          bool found;
>> +
>> +          gsi_vtbl_assign = gsi_for_stmt (stmt);
>
> Why not use 'gsi_virtual_call'?
>

I really do want to use two separate iterators here.  gsi_virtual_call
iterates linearly through all the statements in the basic block.
gsi_vtbl_assign gets moved around a bit, later down in the code, to
find the exact position for inserting the verification call.

>>
>> +                  if (TREE_CODE (vtbl_decl) == VAR_DECL)
>> +                    vtable_name = IDENTIFIER_POINTER (DECL_NAME (vtbl_decl));
>> +
>> +                  push_gimplify_context (&gctx);
>
> Not needed.  You are not calling the gimplifier.
>

Ok.

>>
>> +
>> +          if (!next_stmt)
>> +            {
>> +              pop_gimplify_context (NULL);
>
> Likewise.

Ok.

>
>>
>> +          gsi_insert_after (&gsi_vtbl_assign, call_stmt,
>> +                    GSI_NEW_STMT);
>> +
>> +                  pop_gimplify_context (NULL);
>
> Likewise.
>

Ok.
>
> Diego.

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2013-05-24 20:52 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-02-25 19:28 [PATCH, updated] Vtable pointer verification, main gcc changes (patch 2 of 3) Caroline Tice
2013-03-07 23:55 ` Caroline Tice
2013-03-13 17:48 ` Diego Novillo
2013-05-24 20:52   ` Caroline Tice

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).