re PR c++/70035 (Calling a non-virtual member in base-class constructor call with...
authorJakub Jelinek <jakub@redhat.com>
Fri, 4 Mar 2016 22:10:49 +0000 (23:10 +0100)
committerJakub Jelinek <jakub@gcc.gnu.org>
Fri, 4 Mar 2016 22:10:49 +0000 (23:10 +0100)
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
gcc/cp/cp-tree.h
gcc/cp/cp-ubsan.c
gcc/cp/decl.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/ubsan/pr70035.C [new file with mode: 0644]

index 4db438b8eab5526d040a67ded097e3371a127c3c..1bfb146bf37d3ee023a123e326816ed1eda47adc 100644 (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
index b1dc23cb5df1ae6d1ecb6e1fa82a90ee46fa5ad9..7de0a55e3f5965b6126e43114cdca77b1f2f9231 100644 (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++ */
 
index a5aefcf70bb286360b8dfae589a8342de3ec0aed..2ad0a26207f33f42e924b59d33460bdbc1ed781b 100644 (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);
+}
index 5ec65892e68df0e30499612dc2be45e9ed32978d..0edf1665b014fcda524ff0b8262ed8adfeec796a 100644 (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;
 }
 
index 763364ff42ff3bdb15bfcfb86b0f5a2ee7d03be6..c97c20d567392b1c99183d76c3a932400f4218d2 100644 (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.
 
diff --git a/gcc/testsuite/g++.dg/ubsan/pr70035.C b/gcc/testsuite/g++.dg/ubsan/pr70035.C
new file mode 100644 (file)
index 0000000..a1d3dc2
--- /dev/null
@@ -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" }