aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2016-03-04 23:10:49 +0100
committerJakub Jelinek <jakub@gcc.gnu.org>2016-03-04 23:10:49 +0100
commit0c8825de94f416f4e76720f769f26e21c80d328c (patch)
tree8a513c754cfa209a3137cc23ee5567d3dfd1c8f6
parent188e53bd7e191526f2c6804601c031f8f7c53e14 (diff)
downloadgcc-0c8825de94f416f4e76720f769f26e21c80d328c.zip
gcc-0c8825de94f416f4e76720f769f26e21c80d328c.tar.gz
gcc-0c8825de94f416f4e76720f769f26e21c80d328c.tar.bz2
re PR c++/70035 (Calling a non-virtual member in base-class constructor call with ubsan causes segfault when superclass has virtual member with same name)
PR c++/70035 * cp-tree.h (cp_ubsan_maybe_initialize_vtbl_ptrs): New prototype. * decl.c (start_preparsed_function): Call cp_ubsan_maybe_initialize_vtbl_ptrs if needed. * cp-ubsan.c (cp_ubsan_dfs_initialize_vtbl_ptrs, cp_ubsan_maybe_initialize_vtbl_ptrs): New functions. * g++.dg/ubsan/pr70035.C: New test. From-SVN: r233984
-rw-r--r--gcc/cp/ChangeLog9
-rw-r--r--gcc/cp/cp-tree.h1
-rw-r--r--gcc/cp/cp-ubsan.c52
-rw-r--r--gcc/cp/decl.c7
-rw-r--r--gcc/testsuite/ChangeLog3
-rw-r--r--gcc/testsuite/g++.dg/ubsan/pr70035.C26
6 files changed, 98 insertions, 0 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 4db438b..1bfb146 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,12 @@
+2016-03-04 Jakub Jelinek <jakub@redhat.com>
+
+ PR c++/70035
+ * cp-tree.h (cp_ubsan_maybe_initialize_vtbl_ptrs): New prototype.
+ * decl.c (start_preparsed_function): Call
+ cp_ubsan_maybe_initialize_vtbl_ptrs if needed.
+ * cp-ubsan.c (cp_ubsan_dfs_initialize_vtbl_ptrs,
+ cp_ubsan_maybe_initialize_vtbl_ptrs): New functions.
+
2016-03-04 Jason Merrill <jason@redhat.com>
PR c++/67364
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index b1dc23c..7de0a55 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -6940,6 +6940,7 @@ extern void cp_ubsan_maybe_instrument_member_call (tree);
extern void cp_ubsan_instrument_member_accesses (tree *);
extern tree cp_ubsan_maybe_instrument_downcast (location_t, tree, tree, tree);
extern tree cp_ubsan_maybe_instrument_cast_to_vbase (location_t, tree, tree);
+extern void cp_ubsan_maybe_initialize_vtbl_ptrs (tree);
/* -- end of C++ */
diff --git a/gcc/cp/cp-ubsan.c b/gcc/cp/cp-ubsan.c
index a5aefcf..2ad0a26 100644
--- a/gcc/cp/cp-ubsan.c
+++ b/gcc/cp/cp-ubsan.c
@@ -272,3 +272,55 @@ cp_ubsan_maybe_instrument_cast_to_vbase (location_t loc, tree type, tree op)
return cp_ubsan_maybe_instrument_vptr (loc, op, type, true,
UBSAN_CAST_TO_VBASE);
}
+
+/* Called from initialize_vtbl_ptrs via dfs_walk. BINFO is the base
+ which we want to initialize the vtable pointer for, DATA is
+ TREE_LIST whose TREE_VALUE is the this ptr expression. */
+
+static tree
+cp_ubsan_dfs_initialize_vtbl_ptrs (tree binfo, void *data)
+{
+ if (!TYPE_CONTAINS_VPTR_P (BINFO_TYPE (binfo)))
+ return dfs_skip_bases;
+
+ if (!BINFO_PRIMARY_P (binfo) || BINFO_VIRTUAL_P (binfo))
+ {
+ tree base_ptr = TREE_VALUE ((tree) data);
+
+ base_ptr = build_base_path (PLUS_EXPR, base_ptr, binfo, /*nonnull=*/1,
+ tf_warning_or_error);
+
+ /* Compute the location of the vtpr. */
+ tree vtbl_ptr
+ = build_vfield_ref (cp_build_indirect_ref (base_ptr, RO_NULL,
+ tf_warning_or_error),
+ TREE_TYPE (binfo));
+ gcc_assert (vtbl_ptr != error_mark_node);
+
+ /* Assign NULL to the vptr. */
+ tree vtbl = build_zero_cst (TREE_TYPE (vtbl_ptr));
+ finish_expr_stmt (cp_build_modify_expr (vtbl_ptr, NOP_EXPR, vtbl,
+ tf_warning_or_error));
+ }
+
+ return NULL_TREE;
+}
+
+/* Initialize all the vtable pointers in the object pointed to by
+ ADDR to NULL, so that we catch invalid calls to methods before
+ mem-initializers are completed. */
+
+void
+cp_ubsan_maybe_initialize_vtbl_ptrs (tree addr)
+{
+ if (!cp_ubsan_instrument_vptr_p (NULL_TREE))
+ return;
+
+ tree type = TREE_TYPE (TREE_TYPE (addr));
+ tree list = build_tree_list (type, addr);
+
+ /* Walk through the hierarchy, initializing the vptr in each base
+ class to NULL. */
+ dfs_walk_once (TYPE_BINFO (type), cp_ubsan_dfs_initialize_vtbl_ptrs,
+ NULL, list);
+}
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 5ec6589..0edf166 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -14136,6 +14136,13 @@ start_preparsed_function (tree decl1, tree attrs, int flags)
finish_expr_stmt (exprstmt);
}
+ if (!processing_template_decl
+ && DECL_CONSTRUCTOR_P (decl1)
+ && (flag_sanitize & SANITIZE_VPTR)
+ && !DECL_CLONED_FUNCTION_P (decl1)
+ && !implicit_default_ctor_p (decl1))
+ cp_ubsan_maybe_initialize_vtbl_ptrs (current_class_ptr);
+
return true;
}
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 763364f..c97c20d 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,5 +1,8 @@
2016-03-04 Jakub Jelinek <jakub@redhat.com>
+ PR c++/70035
+ * g++.dg/ubsan/pr70035.C: New test.
+
PR target/70062
* gcc.target/i386/pr70062.c: New test.
diff --git a/gcc/testsuite/g++.dg/ubsan/pr70035.C b/gcc/testsuite/g++.dg/ubsan/pr70035.C
new file mode 100644
index 0000000..a1d3dc2
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ubsan/pr70035.C
@@ -0,0 +1,26 @@
+// PR c++/70035
+// { dg-do run }
+// { dg-shouldfail "ubsan" }
+// { dg-options "-fsanitize=vptr -fno-sanitize-recover=undefined" }
+
+struct A {
+ A (int) {}
+ virtual int foo () { return 1; }
+};
+struct B : public A {
+ using A::foo;
+ B (int x) : A (foo (x)) {}
+ int foo (int x) { return x * 2; }
+};
+
+int
+main ()
+{
+ B b (20);
+}
+
+// { dg-output "\[^\n\r]*pr70035.C:12:\[0-9]*: runtime error: member call on address 0x\[0-9a-fA-F]* which does not point to an object of type 'B'(\n|\r\n|\r)" }
+// { dg-output "0x\[0-9a-fA-F]*: note: object has invalid vptr(\n|\r\n|\r)" }
+// { dg-output " ?.. .. .. .. ?.. .. .. .. ?.. .. .. .. \[^\n\r]*(\n|\r\n|\r)" }
+// { dg-output " ?\\^~~~~~~~~~~\[^\n\r]*(\n|\r\n|\r)" }
+// { dg-output " ?invalid vptr" }