* [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).