Hi!

As mentioned in the PR, if some class has nearly empty virtual base as
primary base, it shares the vptr with that primary base; in that case,
we can't clear the vptr in the not in charge destructor of that class,
as the dtor for the virtual base will be invoked later on and needs to have
the virtual pointer non-NULL.

This version differs from the originally pasted into the PR by the
convert_to_void, so that with -O0 we don't emit an unnecessary load from the
vptr after the store (+ testcase).

Fixed thusly, bootstrapped/regtested on x86_64-linux and i686-linux, ok for
trunk and after a while release branches?

2018-08-28  Jakub Jelinek  <ja...@redhat.com>

        PR c++/87095
        * decl.c (begin_destructor_body): If current_class_type has
        virtual bases and the primary base is nearly empty virtual base,
        voidify clearing of vptr and make it conditional on in-charge
        argument.

        * g++.dg/ubsan/vptr-13.C: New test.

--- gcc/cp/decl.c.jj    2018-08-27 17:50:43.781489594 +0200
+++ gcc/cp/decl.c       2018-08-28 14:41:01.354365914 +0200
@@ -15696,6 +15696,18 @@ begin_destructor_body (void)
            tree stmt = cp_build_modify_expr (input_location, vtbl_ptr,
                                              NOP_EXPR, vtbl,
                                              tf_warning_or_error);
+           /* If the vptr is shared with some virtual nearly empty base,
+              don't clear it if not in charge, the dtor of the virtual
+              nearly empty base will do that later.  */
+           if (CLASSTYPE_VBASECLASSES (current_class_type)
+               && CLASSTYPE_PRIMARY_BINFO (current_class_type)
+               && BINFO_VIRTUAL_P
+                         (CLASSTYPE_PRIMARY_BINFO (current_class_type)))
+             {
+               stmt = convert_to_void (stmt, ICV_STATEMENT,
+                                       tf_warning_or_error);
+               stmt = build_if_in_charge (stmt);
+             }
            finish_decl_cleanup (NULL_TREE, stmt);
          }
        else
--- gcc/testsuite/g++.dg/ubsan/vptr-13.C.jj     2018-08-28 14:50:18.712112488 
+0200
+++ gcc/testsuite/g++.dg/ubsan/vptr-13.C        2018-08-28 14:49:17.895122080 
+0200
@@ -0,0 +1,19 @@
+// PR c++/87095
+// { dg-do run }
+// { dg-options "-fsanitize=vptr -fno-sanitize-recover=vptr" }
+
+struct A
+{
+  virtual ~A () {}
+};
+
+struct B : virtual A {};
+
+struct C : B {};
+
+int
+main ()
+{
+  C c;
+  return 0;
+}

        Jakub

Reply via email to