[pushed] c++: vptr ubsan and object of known type [PR95466]

Message ID 20200601205238.12339-1-jason@redhat.com
State New
Headers show
Series
  • [pushed] c++: vptr ubsan and object of known type [PR95466]
Related show

Commit Message

Kees Cook via Gcc-patches June 1, 2020, 8:52 p.m.
Another case where we can't find the OBJ_TYPE_REF_OBJECT in the
OBJ_TYPE_REF_EXPR.  So let's just evaluate the sanitize call first.

Tested x86_64-pc-linux-gnu, applying to trunk.

gcc/cp/ChangeLog:

	PR c++/95466
	PR c++/95311
	PR c++/95221
	* class.c (build_vfn_ref): Revert 95311 change.
	* cp-ubsan.c (cp_ubsan_maybe_instrument_member_call): Build a
	COMPOUND_EXPR.

gcc/testsuite/ChangeLog:

	PR c++/95466
	* g++.dg/ubsan/vptr-17.C: New test.
---
 gcc/cp/class.c                       |  8 ++------
 gcc/cp/cp-ubsan.c                    | 17 ++++++++---------
 gcc/testsuite/g++.dg/ubsan/vptr-17.C | 15 +++++++++++++++
 3 files changed, 25 insertions(+), 15 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ubsan/vptr-17.C


base-commit: 88f48e2967ead9be262483618238efa9c7c842ec
-- 
2.18.1

Patch

diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index c818826a108..757e010b6b7 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -729,13 +729,9 @@  build_vtbl_ref (tree instance, tree idx)
 tree
 build_vfn_ref (tree instance_ptr, tree idx)
 {
-  tree obtype = TREE_TYPE (TREE_TYPE (instance_ptr));
+  tree aref;
 
-  /* Leave the INDIRECT_REF unfolded so cp_ubsan_maybe_instrument_member_call
-     can find instance_ptr.  */
-  tree ind = build1 (INDIRECT_REF, obtype, instance_ptr);
-
-  tree aref = build_vtbl_ref (ind, idx);
+  aref = build_vtbl_ref (cp_build_fold_indirect_ref (instance_ptr), idx);
 
   /* When using function descriptors, the address of the
      vtable entry is treated as a function pointer.  */
diff --git a/gcc/cp/cp-ubsan.c b/gcc/cp/cp-ubsan.c
index c40dac72b42..183bd238aff 100644
--- a/gcc/cp/cp-ubsan.c
+++ b/gcc/cp/cp-ubsan.c
@@ -125,16 +125,11 @@  cp_ubsan_maybe_instrument_member_call (tree stmt)
     {
       /* Virtual function call: Sanitize the use of the object pointer in the
 	 OBJ_TYPE_REF, since the vtable reference will SEGV otherwise (95221).
-	 OBJ_TYPE_REF_EXPR is ptr->vptr[N] and OBJ_TYPE_REF_OBJECT is ptr.  */
+	 OBJ_TYPE_REF_EXPR is ptr->vptr[N] and OBJ_TYPE_REF_OBJECT is ptr.  But
+	 we can't be sure of finding OBJ_TYPE_REF_OBJECT in OBJ_TYPE_REF_EXPR
+	 if the latter has been optimized, so we use a COMPOUND_EXPR below.  */
       opp = &OBJ_TYPE_REF_EXPR (fn);
       op = OBJ_TYPE_REF_OBJECT (fn);
-      while (*opp != op)
-	{
-	  if (TREE_CODE (*opp) == COMPOUND_EXPR)
-	    opp = &TREE_OPERAND (*opp, 1);
-	  else
-	    opp = &TREE_OPERAND (*opp, 0);
-	}
     }
   else
     {
@@ -150,7 +145,11 @@  cp_ubsan_maybe_instrument_member_call (tree stmt)
   op = cp_ubsan_maybe_instrument_vptr (EXPR_LOCATION (stmt), op,
 				       TREE_TYPE (TREE_TYPE (op)),
 				       true, UBSAN_MEMBER_CALL);
-  if (op)
+  if (!op)
+    /* No change.  */;
+  else if (fn && TREE_CODE (fn) == OBJ_TYPE_REF)
+    *opp = cp_build_compound_expr (op, *opp, tf_none);
+  else
     *opp = op;
 }
 
diff --git a/gcc/testsuite/g++.dg/ubsan/vptr-17.C b/gcc/testsuite/g++.dg/ubsan/vptr-17.C
new file mode 100644
index 00000000000..b7f6a4cb4df
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ubsan/vptr-17.C
@@ -0,0 +1,15 @@ 
+// PR c++/95466
+// { dg-additional-options -fsanitize=vptr }
+
+class A {
+  virtual void m_fn1();
+};
+class C {
+public:
+  virtual void m_fn2();
+};
+class B : A, public C {};
+int main() {
+  B b;
+  static_cast<C *>(&b)->m_fn2();
+}