[libcxxabi] r276016 - [libcxxabi] When catching an exception of type nullptr_t with a handler of

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Tue Jul 19 13:19:37 PDT 2016


Author: rsmith
Date: Tue Jul 19 15:19:37 2016
New Revision: 276016

URL: http://llvm.org/viewvc/llvm-project?rev=276016&view=rev
Log:
[libcxxabi] When catching an exception of type nullptr_t with a handler of
pointer-to-member type, produce a null value of the right type.

This fixes a bug where throwing an exception of type nullptr_t and catching it
as a pointer-to-member would not guarantee to produce a null value in the catch
handler. The fix is pretty simple: we statically allocate a constant null
pointer-to-data-member representation and a constant null
pointer-to-member-function representation, and produce the address of the
relevant value as the adjusted pointer for the exception.

Added:
    libcxxabi/trunk/test/catch_reference_nullptr.pass.cpp
Modified:
    libcxxabi/trunk/src/private_typeinfo.cpp
    libcxxabi/trunk/test/catch_const_pointer_nullptr.pass.cpp
    libcxxabi/trunk/test/catch_member_pointer_nullptr.pass.cpp
    libcxxabi/trunk/test/catch_pointer_nullptr.pass.cpp
    libcxxabi/trunk/test/incomplete_type.sh.cpp

Modified: libcxxabi/trunk/src/private_typeinfo.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxxabi/trunk/src/private_typeinfo.cpp?rev=276016&r1=276015&r2=276016&view=diff
==============================================================================
--- libcxxabi/trunk/src/private_typeinfo.cpp (original)
+++ libcxxabi/trunk/src/private_typeinfo.cpp Tue Jul 19 15:19:37 2016
@@ -171,8 +171,12 @@ __pointer_to_member_type_info::~__pointe
 // catch (D2& d2) : adjustedPtr == &d2  (d2 is base class of thrown object)
 // catch (D2* d2) : adjustedPtr == d2
 // catch (D2*& d2) : adjustedPtr == d2
-// 
+//
 // catch (...) : adjustedPtr == & of the exception
+//
+// If the thrown type is nullptr_t and the caught type is a pointer to
+// member type, adjustedPtr points to a statically-allocated null pointer
+// representation of that type.
 
 // Handles bullet 1
 bool
@@ -337,12 +341,11 @@ __vmi_class_type_info::has_unambiguous_p
     }
 }
 
-// Handles bullets 1 and 4 for both pointers and member pointers
+// Handles bullet 1 for both pointers and member pointers
 bool
 __pbase_type_info::can_catch(const __shim_type_info* thrown_type,
                              void*&) const
 {
-    if (is_equal(thrown_type, &typeid(std::nullptr_t), false)) return true;
     bool use_strcmp = this->__flags & (__incomplete_class_mask |
                                        __incomplete_mask);
     if (!use_strcmp) {
@@ -367,7 +370,13 @@ bool
 __pointer_type_info::can_catch(const __shim_type_info* thrown_type,
                                void*& adjustedPtr) const
 {
-    // bullets 1 and 4
+    // bullet 4
+    if (is_equal(thrown_type, &typeid(std::nullptr_t), false)) {
+      adjustedPtr = nullptr;
+      return true;
+    }
+
+    // bullet 1
     if (__pbase_type_info::can_catch(thrown_type, adjustedPtr)) {
         if (adjustedPtr != NULL)
             adjustedPtr = *static_cast<void**>(adjustedPtr);
@@ -468,7 +477,22 @@ bool __pointer_type_info::can_catch_nest
 
 bool __pointer_to_member_type_info::can_catch(
     const __shim_type_info* thrown_type, void*& adjustedPtr) const {
-    // bullets 1 and 4
+    // bullet 4
+    if (is_equal(thrown_type, &typeid(std::nullptr_t), false)) {
+      // We assume that the pointer to member representation is the same for
+      // all pointers to data members and for all pointers to member functions.
+      struct X {};
+      if (dynamic_cast<const __function_type_info*>(__pointee)) {
+        static int (X::*const null_ptr_rep)() = nullptr;
+        adjustedPtr = const_cast<int (X::**)()>(&null_ptr_rep);
+      } else {
+        static int X::*const null_ptr_rep = nullptr;
+        adjustedPtr = const_cast<int X::**>(&null_ptr_rep);
+      }
+      return true;
+    }
+
+    // bullet 1
     if (__pbase_type_info::can_catch(thrown_type, adjustedPtr))
         return true;
 

Modified: libcxxabi/trunk/test/catch_const_pointer_nullptr.pass.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxxabi/trunk/test/catch_const_pointer_nullptr.pass.cpp?rev=276016&r1=276015&r2=276016&view=diff
==============================================================================
--- libcxxabi/trunk/test/catch_const_pointer_nullptr.pass.cpp (original)
+++ libcxxabi/trunk/test/catch_const_pointer_nullptr.pass.cpp Tue Jul 19 15:19:37 2016
@@ -29,8 +29,9 @@ void test1()
         throw nullptr;
         assert(false);
     }
-    catch (A*)
+    catch (A* p)
     {
+        assert(!p);
     }
     catch (const A*)
     {
@@ -46,8 +47,9 @@ void test2()
         throw nullptr;
         assert(false);
     }
-    catch (const A*)
+    catch (const A* p)
     {
+        assert(!p);
     }
     catch (A*)
     {
@@ -62,8 +64,9 @@ void test3()
         throw nullptr;
         assert(false);
     }
-    catch (const A* const)
+    catch (const A* const p)
     {
+        assert(!p);
     }
     catch (A*)
     {
@@ -78,8 +81,9 @@ void test4()
         throw nullptr;
         assert(false);
     }
-    catch (A*)
+    catch (A* p)
     {
+        assert(!p);
     }
     catch (const A* const)
     {
@@ -94,8 +98,9 @@ void test5()
         throw nullptr;
         assert(false);
     }
-    catch (A const*)
+    catch (A const* p)
     {
+        assert(!p);
     }
     catch (A*)
     {
@@ -110,8 +115,9 @@ void test6()
         throw nullptr;
         assert(false);
     }
-    catch (A*)
+    catch (A* p)
     {
+        assert(!p);
     }
     catch (A const*)
     {

Modified: libcxxabi/trunk/test/catch_member_pointer_nullptr.pass.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxxabi/trunk/test/catch_member_pointer_nullptr.pass.cpp?rev=276016&r1=276015&r2=276016&view=diff
==============================================================================
--- libcxxabi/trunk/test/catch_member_pointer_nullptr.pass.cpp (original)
+++ libcxxabi/trunk/test/catch_member_pointer_nullptr.pass.cpp Tue Jul 19 15:19:37 2016
@@ -29,8 +29,9 @@ void test1()
         throw nullptr;
         assert(false);
     }
-    catch (md2)
+    catch (md2 p)
     {
+        assert(!p);
     }
     catch (md1)
     {
@@ -45,8 +46,9 @@ void test2()
         throw nullptr;
         assert(false);
     }
-    catch (md1)
+    catch (md1 p)
     {
+        assert(!p);
     }
     catch (md2)
     {

Modified: libcxxabi/trunk/test/catch_pointer_nullptr.pass.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxxabi/trunk/test/catch_pointer_nullptr.pass.cpp?rev=276016&r1=276015&r2=276016&view=diff
==============================================================================
--- libcxxabi/trunk/test/catch_pointer_nullptr.pass.cpp (original)
+++ libcxxabi/trunk/test/catch_pointer_nullptr.pass.cpp Tue Jul 19 15:19:37 2016
@@ -21,8 +21,9 @@ void test1()
         throw nullptr;
         assert(false);
     }
-    catch (int*)
+    catch (int* p)
     {
+        assert(!p);
     }
     catch (long*)
     {
@@ -37,8 +38,9 @@ void test2()
         throw nullptr;
         assert(false);
     }
-    catch (A*)
+    catch (A* p)
     {
+        assert(!p);
     }
     catch (int*)
     {
@@ -51,8 +53,8 @@ void catch_nullptr_test() {
   try {
     throw nullptr;
     assert(false);
-  } catch (Catch) {
-    // nothing todo
+  } catch (Catch c) {
+    assert(!c);
   } catch (...) {
     assert(false);
   }

Added: libcxxabi/trunk/test/catch_reference_nullptr.pass.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxxabi/trunk/test/catch_reference_nullptr.pass.cpp?rev=276016&view=auto
==============================================================================
--- libcxxabi/trunk/test/catch_reference_nullptr.pass.cpp (added)
+++ libcxxabi/trunk/test/catch_reference_nullptr.pass.cpp Tue Jul 19 15:19:37 2016
@@ -0,0 +1,49 @@
+//===--------------------- catch_pointer_nullptr.cpp ----------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03, libcxxabi-no-exceptions
+
+#include <cassert>
+#include <cstdlib>
+
+struct A {};
+
+template<typename T, bool CanCatchNullptr>
+static void catch_nullptr_test() {
+  try {
+    throw nullptr;
+  } catch (T &p) {
+    assert(CanCatchNullptr && !p);
+  } catch (...) {
+    assert(!CanCatchNullptr);
+  }
+}
+
+int main()
+{
+  using nullptr_t = decltype(nullptr);
+
+  // A reference to nullptr_t can catch nullptr.
+  catch_nullptr_test<nullptr_t, true>();
+  catch_nullptr_test<const nullptr_t, true>();
+  catch_nullptr_test<volatile nullptr_t, true>();
+  catch_nullptr_test<const volatile nullptr_t, true>();
+
+  // No other reference type can.
+#if 0
+  // FIXME: These tests fail, because the ABI provides no way for us to
+  // distinguish this from catching by value.
+  catch_nullptr_test<void *, false>();
+  catch_nullptr_test<void * const, false>();
+  catch_nullptr_test<int *, false>();
+  catch_nullptr_test<A *, false>();
+  catch_nullptr_test<int A::*, false>();
+  catch_nullptr_test<int (A::*)(), false>();
+#endif
+}

Modified: libcxxabi/trunk/test/incomplete_type.sh.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxxabi/trunk/test/incomplete_type.sh.cpp?rev=276016&r1=276015&r2=276016&view=diff
==============================================================================
--- libcxxabi/trunk/test/incomplete_type.sh.cpp (original)
+++ libcxxabi/trunk/test/incomplete_type.sh.cpp Tue Jul 19 15:19:37 2016
@@ -88,7 +88,9 @@ int main() {
     assert(false);
   } catch (int CompleteAtThrow::*) {
     assert(false);
-  } catch (int NeverDefined::*) {}
+  } catch (int NeverDefined::*p) {
+    assert(!p);
+  }
   AssertIncompleteTypeInfoEquals(ReturnTypeInfoIncompleteMP(), typeid(int IncompleteAtThrow::*));
   try {
     ThrowIncompleteMP();
@@ -99,7 +101,9 @@ int main() {
     assert(false);
   } catch (IncompleteAtThrow**) {
     assert(false);
-  } catch (int IncompleteAtThrow::*) {}
+  } catch (int IncompleteAtThrow::*p) {
+    assert(!p);
+  }
 
   AssertIncompleteTypeInfoEquals(ReturnTypeInfoIncompletePP(), typeid(IncompleteAtThrow**));
   try {
@@ -107,7 +111,9 @@ int main() {
     assert(false);
   } catch (int IncompleteAtThrow::*) {
     assert(false);
-  } catch (IncompleteAtThrow**) {}
+  } catch (IncompleteAtThrow** p) {
+    assert(!p);
+  }
 
   try {
     ThrowIncompletePMP();
@@ -116,7 +122,9 @@ int main() {
     assert(false);
   } catch (IncompleteAtThrow**) {
     assert(false);
-  } catch (int IncompleteAtThrow::**) {}
+  } catch (int IncompleteAtThrow::**p) {
+    assert(!p);
+  }
 
   AssertIncompleteTypeInfoEquals(ReturnTypeInfoCompleteMP(), typeid(int CompleteAtThrow::*));
   try {
@@ -128,7 +136,9 @@ int main() {
     assert(false);
   } catch (CompleteAtThrow**) {
     assert(false);
-  } catch (int CompleteAtThrow::*) {}
+  } catch (int CompleteAtThrow::*p) {
+    assert(!p);
+  }
 
   AssertIncompleteTypeInfoEquals(ReturnTypeInfoCompletePP(), typeid(CompleteAtThrow**));
   try {
@@ -140,7 +150,9 @@ int main() {
     assert(false);
   } catch (int CompleteAtThrow::*) {
     assert(false);
-  } catch (CompleteAtThrow**) {}
+  } catch (CompleteAtThrow**p) {
+    assert(!p);
+  }
 
   try {
     ThrowCompletePMP();
@@ -153,22 +165,30 @@ int main() {
     assert(false);
   } catch (CompleteAtThrow**) {
     assert(false);
-  } catch (int CompleteAtThrow::**) {}
+  } catch (int CompleteAtThrow::**p) {
+    assert(!p);
+  }
 
 #if __cplusplus >= 201103L
   // Catch nullptr as complete type
   try {
     ThrowNullptr();
-  } catch (int IncompleteAtThrow::*) {}
+  } catch (int IncompleteAtThrow::*p) {
+    assert(!p);
+  }
 
   // Catch nullptr as an incomplete type
   try {
     ThrowNullptr();
-  } catch (int CompleteAtThrow::*) {}
+  } catch (int CompleteAtThrow::*p) {
+    assert(!p);
+  }
   // Catch nullptr as a type that is never complete.
   try {
     ThrowNullptr();
-  } catch (int NeverDefined::*) {}
+  } catch (int NeverDefined::*p) {
+    assert(!p);
+  }
 #endif
 }
 #endif




More information about the cfe-commits mailing list