+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
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++ */
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);
+}
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;
}
--- /dev/null
+// 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" }