c++: vptr ubsan and object of known type [PR95466]
authorJason Merrill <jason@redhat.com>
Mon, 1 Jun 2020 20:20:38 +0000 (16:20 -0400)
committerJason Merrill <jason@redhat.com>
Mon, 1 Jun 2020 20:52:47 +0000 (16:52 -0400)
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.

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
gcc/cp/cp-ubsan.c
gcc/testsuite/g++.dg/ubsan/vptr-17.C [new file with mode: 0644]

index c818826..757e010 100644 (file)
@@ -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));
-
-  /* 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;
 
-  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.  */
index c40dac7..183bd23 100644 (file)
@@ -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 (file)
index 0000000..b7f6a4c
--- /dev/null
@@ -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();
+}