[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