[libcxxabi] Disallow Base to Derived conversions for catching pointers to members.
authorEric Fiselier <eric@efcs.ca>
Mon, 6 Apr 2015 23:03:01 +0000 (23:03 +0000)
committerEric Fiselier <eric@efcs.ca>
Mon, 6 Apr 2015 23:03:01 +0000 (23:03 +0000)
Summary:
I accidentally implemented the 4.11 [conv.mem] conversions for libc++abi in a recent patch. @majnemer pointed out that 5.13 [except.handle] only allows the pointer conversions in 4.10 and not those is 4.11. This patch no longer allows the following example code:

```c++
struct A {};
struct B : public A {};

int main() {
  try {
    throw (int A::*)0;
  } catch (int B::*) {
    // exception caught here.
  }
}
```

Reviewers: mclow.lists, jroelofs, majnemer

Reviewed By: majnemer

Subscribers: majnemer, cfe-commits

Differential Revision: http://reviews.llvm.org/D8845

llvm-svn: 234254

libcxxabi/src/private_typeinfo.cpp
libcxxabi/test/catch_member_data_pointer_01.pass.cpp
libcxxabi/test/catch_member_function_pointer_01.pass.cpp
libcxxabi/test/catch_multi_level_pointer.pass.cpp

index 65cb6ed..590906a 100644 (file)
@@ -479,11 +479,9 @@ bool __pointer_to_member_type_info::can_catch(
     if (is_equal(__context, thrown_pointer_type->__context, false))
         return true;
 
-    __dynamic_cast_info info = {__context, 0, thrown_pointer_type->__context, -1, 0};
-    info.number_of_dst_type = 1;
-    __context->has_unambiguous_public_base(&info, adjustedPtr, public_path);
-    if (info.path_dst_ptr_to_static_ptr == public_path)
-        return true;
+    // [except.handle] does not allow the pointer-to-member conversions mentioned
+    // in [mem.conv] to take place. For this reason we don't check Derived->Base
+    // for Derived->Base conversions.
 
     return false;
 }
index 298a1c0..28bf4b5 100644 (file)
@@ -72,7 +72,7 @@ void test2()
     }
 }
 
-// Check that Base -> Derived conversions are allowed.
+// Check that Base -> Derived conversions are NOT allowed.
 void test3()
 {
     try
@@ -90,14 +90,14 @@ void test3()
     }
     catch (der1)
     {
+        assert(false);
     }
     catch (md1)
     {
-        assert(false);
     }
 }
 
-// Check that Base -> Derived conversions are allowed with different cv
+// Check that Base -> Derived conversions NOT are allowed with different cv
 // qualifiers.
 void test4()
 {
@@ -108,18 +108,13 @@ void test4()
     }
     catch (der2)
     {
-    }
-    catch (...)
-    {
         assert(false);
     }
-
-    try
+    catch (der1)
     {
-        throw &A::j;
         assert(false);
     }
-    catch (der1)
+    catch (md2)
     {
     }
     catch (...)
index 4503d88..28b13cc 100644 (file)
@@ -18,6 +18,20 @@ struct A
 typedef void (A::*mf1)();
 typedef void (A::*mf2)() const;
 
+struct B : public A
+{
+};
+
+typedef void (B::*dmf1)();
+typedef void (B::*dmf2)() const;
+
+template <class Tp>
+bool can_convert(Tp) { return true; }
+
+template <class>
+bool can_convert(...) { return false; }
+
+
 void test1()
 {
     try
@@ -50,8 +64,104 @@ void test2()
     }
 }
 
+
+
+void test_derived()
+{
+    try
+    {
+        throw (mf1)0;
+        assert(false);
+    }
+    catch (dmf2)
+    {
+       assert(false);
+    }
+    catch (dmf1)
+    {
+       assert(false);
+    }
+    catch (mf1)
+    {
+    }
+
+    try
+    {
+        throw (mf2)0;
+        assert(false);
+    }
+    catch (dmf1)
+    {
+       assert(false);
+    }
+    catch (dmf2)
+    {
+       assert(false);
+    }
+    catch (mf2)
+    {
+    }
+
+    assert(!can_convert<mf1>((dmf1)0));
+    assert(!can_convert<mf2>((dmf1)0));
+    try
+    {
+        throw (dmf1)0;
+        assert(false);
+    }
+    catch (mf2)
+    {
+       assert(false);
+    }
+    catch (mf1)
+    {
+       assert(false);
+    }
+    catch (...)
+    {
+    }
+
+    assert(!can_convert<mf1>((dmf2)0));
+    assert(!can_convert<mf2>((dmf2)0));
+    try
+    {
+        throw (dmf2)0;
+        assert(false);
+    }
+    catch (mf2)
+    {
+       assert(false);
+    }
+    catch (mf1)
+    {
+        assert(false);
+    }
+    catch (...)
+    {
+    }
+}
+
+void test_void()
+{
+    assert(!can_convert<void*>(&A::foo));
+    try
+    {
+        throw &A::foo;
+        assert(false);
+    }
+    catch (void*)
+    {
+        assert(false);
+    }
+    catch(...)
+    {
+    }
+}
+
 int main()
 {
     test1();
     test2();
+    test_derived();
+    test_void();
 }
index d722ea0..3246099 100644 (file)
@@ -140,6 +140,4 @@ int main()
   generate_tests<int A::*, int A::*, 3>()();
   generate_tests<int A::*, void, 2>()();
   generate_tests<void, int A::*, 2>()();
-  generate_tests<int Base::*, int Derived::*, 2>()();
-  generate_tests<int Derived::*, int Base::*, 2>()();
 }