Zero vptr in dtor for -fsanitize=vptr.
authorMartin Liska <mliska@suse.cz>
Wed, 15 Nov 2017 07:01:01 +0000 (08:01 +0100)
committerMartin Liska <marxin@gcc.gnu.org>
Wed, 15 Nov 2017 07:01:01 +0000 (07:01 +0000)
2017-11-15  Martin Liska  <mliska@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.
2017-11-15  Martin Liska  <mliska@suse.cz>

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

From-SVN: r254754

gcc/cp/ChangeLog
gcc/cp/decl.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/ubsan/vptr-12.C [new file with mode: 0644]

index 8ba5b78aac23d62ca8ef97b8083e66387e855374..578299ef0e26b16d594356418f67b8b9094fb4d5 100644 (file)
@@ -1,3 +1,9 @@
+2017-11-15  Martin Liska  <mliska@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.
+
 2017-11-14  Jason Merrill  <jason@redhat.com>
 
        Use GTY((cache)) on some hash tables.
index c4eb28d14e2a9a9d51e2d05a8bc1ae49b9feb8ee..041893db937443a5f7d9302a202c8769981d0ba4 100644 (file)
@@ -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.  */
index 1cd0070c82edd99e5cae25d1e3114166175b1734..fd2b5d049ea0f9da9283826ffadffa374e6b4156 100644 (file)
@@ -1,3 +1,7 @@
+2017-11-15  Martin Liska  <mliska@suse.cz>
+
+       * g++.dg/ubsan/vptr-12.C: New test.
+
 2017-11-15  Joseph Myers  <joseph@codesourcery.com>
 
        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 (file)
index 0000000..f23bbc3
--- /dev/null
@@ -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" }