diff options
author | Jakub Jelinek <jakub@redhat.com> | 2016-03-04 23:10:49 +0100 |
---|---|---|
committer | Jakub Jelinek <jakub@gcc.gnu.org> | 2016-03-04 23:10:49 +0100 |
commit | 0c8825de94f416f4e76720f769f26e21c80d328c (patch) | |
tree | 8a513c754cfa209a3137cc23ee5567d3dfd1c8f6 | |
parent | 188e53bd7e191526f2c6804601c031f8f7c53e14 (diff) | |
download | gcc-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/ChangeLog | 9 | ||||
-rw-r--r-- | gcc/cp/cp-tree.h | 1 | ||||
-rw-r--r-- | gcc/cp/cp-ubsan.c | 52 | ||||
-rw-r--r-- | gcc/cp/decl.c | 7 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 3 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/ubsan/pr70035.C | 26 |
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" } |