public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [C++ PATCH] Improve -fsanitize=vptr (PR c++/70035)
@ 2016-03-04 20:31 Jakub Jelinek
  2016-03-04 22:01 ` Jason Merrill
  0 siblings, 1 reply; 2+ messages in thread
From: Jakub Jelinek @ 2016-03-04 20:31 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches

Hi!

-fsanitize=vptr library side of instrumentation assumes that the vtable
pointers in objects are either NULL, or some vtable pointer, if it is random
garbage, it might crash.
The following patch attempts to clear the vtable pointers in objects next to
the spot where -flifetime-dse=2 clobbers the object.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

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.

	* g++.dg/ubsan/pr70035.C: New test.

--- gcc/cp/cp-tree.h.jj	2016-02-26 08:57:10.000000000 +0100
+++ gcc/cp/cp-tree.h	2016-03-04 14:07:51.045471741 +0100
@@ -6940,6 +6940,7 @@ extern void cp_ubsan_maybe_instrument_me
 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++ */
 
--- gcc/cp/decl.c.jj	2016-02-24 22:33:35.000000000 +0100
+++ gcc/cp/decl.c	2016-03-04 14:53:54.283672876 +0100
@@ -14136,6 +14136,13 @@ start_preparsed_function (tree decl1, tr
       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;
 }
 
--- gcc/cp/cp-ubsan.c.jj	2016-02-24 23:00:44.000000000 +0100
+++ gcc/cp/cp-ubsan.c	2016-03-04 14:07:24.107840416 +0100
@@ -272,3 +272,55 @@ cp_ubsan_maybe_instrument_cast_to_vbase
   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);
+}
--- gcc/testsuite/g++.dg/ubsan/pr70035.C.jj	2016-03-04 14:20:39.234960689 +0100
+++ gcc/testsuite/g++.dg/ubsan/pr70035.C	2016-03-04 14:55:36.988268869 +0100
@@ -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" }

	Jakub

^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: [C++ PATCH] Improve -fsanitize=vptr (PR c++/70035)
  2016-03-04 20:31 [C++ PATCH] Improve -fsanitize=vptr (PR c++/70035) Jakub Jelinek
@ 2016-03-04 22:01 ` Jason Merrill
  0 siblings, 0 replies; 2+ messages in thread
From: Jason Merrill @ 2016-03-04 22:01 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: gcc-patches

OK.

Jason

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2016-03-04 22:01 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-03-04 20:31 [C++ PATCH] Improve -fsanitize=vptr (PR c++/70035) Jakub Jelinek
2016-03-04 22:01 ` Jason Merrill

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).