[PATCH] c++/58796 Make nullptr match exception handlers of pointer type

Jonathan Wakely jwakely@redhat.com
Fri Jul 15 21:07:00 GMT 2016


On 15/07/16 12:47 +0100, Jonathan Wakely wrote:
>diff --git a/libstdc++-v3/libsupc++/pbase_type_info.cc b/libstdc++-v3/libsupc++/pbase_type_info.cc
>index d47fb23..a2993e4 100644
>--- a/libstdc++-v3/libsupc++/pbase_type_info.cc
>+++ b/libstdc++-v3/libsupc++/pbase_type_info.cc
>@@ -38,6 +38,31 @@ __do_catch (const type_info *thr_type,
>     return true;      // same type
> 
> #if __cpp_rtti
>+  if (*thr_type == typeid (nullptr))
>+    {
>+      // A catch handler for any pointer type matches nullptr_t.
>+      if (typeid (*this) == typeid(__pointer_type_info))
>+        {
>+          *thr_obj = nullptr;
>+          return true;
>+        }
>+      else if (typeid (*this) == typeid(__pointer_to_member_type_info))
>+        {
>+          if (__pointee->__is_function_p ())
>+            {
>+              // A pointer-to-member-function is two words <ptr,adj> but the
>+              // nullptr_t exception object at *(nullptr_t*)*thr_obj is only
>+              // one word, so we can't safely return it as a PMF. FIXME.
>+              return false;
>+            }
>+          else
>+            {
>+              *(ptrdiff_t*)*thr_obj = -1; // null pointer to data member

This store could race with accesses in other threads, if the same
exception object gets thrown in multiple threads and the value of the
pointer-to-data-member is read concurrently with the write:

#include <exception>
#include <thread>
#include <cassert>

std::exception_ptr p;

struct A { };

void t()
{
  try {
    std::rethrow_exception(p);
  } catch (int A::* const& e) {
    assert( e == nullptr );
  }
}

int main()
{
  try {
    throw nullptr;
  } catch (...) {
    p = std::current_exception();
  }
  std::thread t1(t);
  std::thread t2(t);
  t1.join();
  t2.join();
}


We could use __atomic_store to do the write, but the reads would still
be non-atomic. The attached patch makes __cxa_throw do that write on
the initial throw, so that a thrown nullptr_t always has the right
content to act as a null pointer-to-member.  However that adds
overhead for every throw. A more efficient solution might be for the
front-end to do that write when it sees a nullptr_t being thrown.


-------------- next part --------------
A non-text attachment was scrubbed...
Name: patch.txt
Type: text/x-patch
Size: 1068 bytes
Desc: not available
URL: <http://gcc.gnu.org/pipermail/gcc-patches/attachments/20160715/cfa06db4/attachment.bin>


More information about the Gcc-patches mailing list