From 896f6b3dfa6fb337109f97bed8d74c1e030c965e Mon Sep 17 00:00:00 2001 From: Martin Liska Date: Wed, 15 Nov 2017 08:01:01 +0100 Subject: [PATCH] Zero vptr in dtor for -fsanitize=vptr. 2017-11-15 Martin Liska * 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. 2017-11-15 Martin Liska * g++.dg/ubsan/vptr-12.C: New test. From-SVN: r254754 --- gcc/cp/ChangeLog | 6 ++++++ gcc/cp/decl.c | 21 ++++++++++++++++++++- gcc/testsuite/ChangeLog | 4 ++++ gcc/testsuite/g++.dg/ubsan/vptr-12.C | 22 ++++++++++++++++++++++ 4 files changed, 52 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/g++.dg/ubsan/vptr-12.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 8ba5b78aac2..578299ef0e2 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,9 @@ +2017-11-15 Martin Liska + + * 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. + 2017-11-14 Jason Merrill Use GTY((cache)) on some hash tables. diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index c4eb28d14e2..041893db937 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -15246,7 +15246,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/ChangeLog b/gcc/testsuite/ChangeLog index 1cd0070c82e..fd2b5d049ea 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2017-11-15 Martin Liska + + * g++.dg/ubsan/vptr-12.C: New test. + 2017-11-15 Joseph Myers PR c/81156 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.30.2