On 11/03/2017 04:21 PM, Jason Merrill wrote: > On Fri, Nov 3, 2017 at 10:25 AM, Martin Liška <mli...@suse.cz> wrote: >> On 10/27/2017 09:44 PM, Nathan Sidwell wrote: >>> On 10/27/2017 02:34 PM, Jakub Jelinek wrote: >>> >>>> But when singly inheriting a polymorphic base and thus mapped to the same >>>> vptr all but the last dtor will not be in charge, right? >>> >>> Correct. >>> >>>> So, if using build_clobber_this for this, instead of clobbering what we >>>> clobber we'd just clear the single vptr (couldn't clobber the rest, even >>>> if before the store, because that would make the earlier other vptr stores >>>> dead). >>> >>> ok (I'd not looked at the patch to see if in chargeness was signficant) >>> >>> nathan >>> >> >> Hello. >> >> I'm sending v2 which only zeros vptr of object. >> >> Ready to be installed after finishing tests? > > Surely we also want to check TYPE_CONTAINS_VPTR_P. > > Jason >
Done that in attached patch. Patch can bootstrap on ppc64le-redhat-linux and survives regression tests. Ready to be installed? Martin
>From 882becbc5446f304a9445281c6f778b80086ce39 Mon Sep 17 00:00:00 2001 From: marxin <mli...@suse.cz> Date: Thu, 19 Oct 2017 11:10:19 +0200 Subject: [PATCH] Zero vptr in dtor for -fsanitize=vptr. gcc/cp/ChangeLog: 2017-11-03 Martin Liska <mli...@suse.cz> * decl.c (begin_destructor_body): In case of VPTR sanitization (with disabled recovery), zero vptr in order to catch virtual calls after lifetime of an object. gcc/testsuite/ChangeLog: 2017-10-27 Martin Liska <mli...@suse.cz> * g++.dg/ubsan/vptr-12.C: New test. --- gcc/cp/decl.c | 21 ++++++++++++++++++++- gcc/testsuite/g++.dg/ubsan/vptr-12.C | 22 ++++++++++++++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/g++.dg/ubsan/vptr-12.C diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 0ce8f2d3435..48d2760afde 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -15247,7 +15247,26 @@ begin_destructor_body (void) if (flag_lifetime_dse /* Clobbering an empty base is harmful if it overlays real data. */ && !is_empty_class (current_class_type)) - finish_decl_cleanup (NULL_TREE, build_clobber_this ()); + { + if (sanitize_flags_p (SANITIZE_VPTR) + && (flag_sanitize_recover & SANITIZE_VPTR) == 0 + && TYPE_CONTAINS_VPTR_P (current_class_type)) + { + tree binfo = TYPE_BINFO (current_class_type); + tree ref + = cp_build_indirect_ref (current_class_ptr, RO_NULL, + tf_warning_or_error); + + tree vtbl_ptr = build_vfield_ref (ref, TREE_TYPE (binfo)); + tree vtbl = build_zero_cst (TREE_TYPE (vtbl_ptr)); + tree stmt = cp_build_modify_expr (input_location, vtbl_ptr, + NOP_EXPR, vtbl, + tf_warning_or_error); + finish_decl_cleanup (NULL_TREE, stmt); + } + else + finish_decl_cleanup (NULL_TREE, build_clobber_this ()); + } /* And insert cleanups for our bases and members so that they will be properly destroyed if we throw. */ diff --git a/gcc/testsuite/g++.dg/ubsan/vptr-12.C b/gcc/testsuite/g++.dg/ubsan/vptr-12.C new file mode 100644 index 00000000000..f23bbc3fd10 --- /dev/null +++ b/gcc/testsuite/g++.dg/ubsan/vptr-12.C @@ -0,0 +1,22 @@ +// { dg-do run } +// { dg-shouldfail "ubsan" } +// { dg-options "-fsanitize=vptr -fno-sanitize-recover=vptr" } + +struct MyClass +{ + virtual ~MyClass () {} + virtual void Doit () {} +}; + +int +main () +{ + MyClass *c = new MyClass; + c->~MyClass (); + c->Doit (); + + return 0; +} + +// { dg-output "\[^\n\r]*vptr-12.C:16:\[0-9]*: runtime error: member call on address 0x\[0-9a-fA-F]* which does not point to an object of type 'MyClass'(\n|\r\n|\r)" } +// { dg-output "0x\[0-9a-fA-F]*: note: object has invalid vptr" } -- 2.14.3