]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
dyncast.cc (__dynamic_cast): Handle mid-destruction dynamic_cast more gracefully.
authorJason Merrill <jason@redhat.com>
Wed, 15 Oct 2014 16:46:17 +0000 (12:46 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Wed, 15 Oct 2014 16:46:17 +0000 (12:46 -0400)
* libsupc++/dyncast.cc (__dynamic_cast): Handle mid-destruction
dynamic_cast more gracefully.

From-SVN: r216274

gcc/testsuite/g++.dg/rtti/dyncast7.C [new file with mode: 0644]
libstdc++-v3/ChangeLog
libstdc++-v3/libsupc++/dyncast.cc

diff --git a/gcc/testsuite/g++.dg/rtti/dyncast7.C b/gcc/testsuite/g++.dg/rtti/dyncast7.C
new file mode 100644 (file)
index 0000000..deb4397
--- /dev/null
@@ -0,0 +1,28 @@
+// I think this dynamic_cast has undefined behavior when destroying E::o
+// because we're the F period of destruction has started and ap doesn't
+// point to the object currently being destroyed--but the reasonable
+// options are success or failure, not SEGV.
+
+// { dg-do run }
+
+extern "C" void abort();
+
+struct A { virtual ~A(); };
+struct B { virtual ~B() { } };
+struct C : B, A { };
+struct E : virtual B { A o; };
+struct F : virtual C, virtual E { };
+
+A* ap;
+C* cp;
+
+A::~A() {
+  C* cp2 = dynamic_cast<C*>(ap);
+  if (cp2 != cp && cp2 != 0)
+    abort();
+}
+
+int main() {
+  F f;
+  ap = cp = &f;
+}
index eb469ba4d83a9dc53d2d93419dcaf8b58edf15f6..22edbcfc40bda41776edcc949f934a981f775393 100644 (file)
@@ -1,3 +1,8 @@
+2014-10-15  Jason Merrill  <jason@redhat.com>
+
+       * libsupc++/dyncast.cc (__dynamic_cast): Handle mid-destruction
+       dynamic_cast more gracefully.
+
 2014-10-14  Kai Tietz  <ktietz@redhat.com>
 
        PR libstdc++/57440
index 2e5dbf0a33d65e3cb934ead980c101ea03144717..b9db8ee5fc41d649771bb4743390b4529ba2c0cc 100644 (file)
@@ -55,6 +55,18 @@ __dynamic_cast (const void *src_ptr,    // object started from
       adjust_pointer <void> (src_ptr, prefix->whole_object);
   const __class_type_info *whole_type = prefix->whole_type;
   __class_type_info::__dyncast_result result;
+
+  // If the whole object vptr doesn't refer to the whole object type, we're
+  // in the middle of constructing a primary base, and src is a separate
+  // base.  This has undefined behavior and we can't find anything outside
+  // of the base we're actually constructing, so fail now rather than
+  // segfault later trying to use a vbase offset that doesn't exist.
+  const void *whole_vtable = *static_cast <const void *const *> (whole_ptr);
+  const vtable_prefix *whole_prefix =
+    adjust_pointer <vtable_prefix> (whole_vtable,
+                                   -offsetof (vtable_prefix, origin));
+  if (whole_prefix->whole_type != whole_type)
+    return NULL;
   
   whole_type->__do_dyncast (src2dst, __class_type_info::__contained_public,
                             dst_type, whole_ptr, src_type, src_ptr, result);