OK.

On Tue, Aug 28, 2018 at 6:39 PM, Jakub Jelinek <ja...@redhat.com> wrote:
> 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