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
This commit is contained in:
Jakub Jelinek 2016-03-04 23:10:49 +01:00 committed by Jakub Jelinek
parent 188e53bd7e
commit 0c8825de94
6 changed files with 98 additions and 0 deletions

View File

@ -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

View File

@ -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++ */

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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.

View File

@ -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" }