From 0c8825de94f416f4e76720f769f26e21c80d328c Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Fri, 4 Mar 2016 23:10:49 +0100 Subject: [PATCH] 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 --- gcc/cp/ChangeLog | 9 +++++ gcc/cp/cp-tree.h | 1 + gcc/cp/cp-ubsan.c | 52 ++++++++++++++++++++++++++++ gcc/cp/decl.c | 7 ++++ gcc/testsuite/ChangeLog | 3 ++ gcc/testsuite/g++.dg/ubsan/pr70035.C | 26 ++++++++++++++ 6 files changed, 98 insertions(+) create mode 100644 gcc/testsuite/g++.dg/ubsan/pr70035.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 4db438b8eab..1bfb146bf37 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,12 @@ +2016-03-04 Jakub Jelinek + + 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 PR c++/67364 diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index b1dc23cb5df..7de0a55e3f5 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 a5aefcf70bb..2ad0a26207f 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 5ec65892e68..0edf1665b01 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 763364ff42f..c97c20d5673 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,5 +1,8 @@ 2016-03-04 Jakub Jelinek + 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 00000000000..a1d3dc2ec16 --- /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" } -- 2.30.2