text: //Copyright (c) 2006-2009 Emil Dotchevski and Reverge Studios, Inc.
  
  //Distributed under the Boost Software License, Version 1.0. (See accompanying
  //file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  
  //This MSVC-specific cpp file implements non-intrusive cloning of exception objects.
  //Based on an exception_ptr implementation by Anthony Williams.
  
  #ifdef BOOST_NO_EXCEPTIONS
  #error This file requires exception handling to be enabled.
  #endif
  
  #include <boost/config.hpp>
  #include <boost/exception/detail/clone_current_exception.hpp>
  
  #if defined(BOOST_ENABLE_NON_INTRUSIVE_EXCEPTION_PTR) && defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64))
  
  //Non-intrusive cloning support implemented below, only for MSVC versions mentioned above.
  //Thanks Anthony Williams!
  //Thanks to Martin Weiss for implementing 64-bit support!
  
  #include <boost/exception/exception.hpp>
  #include <boost/shared_ptr.hpp>
  #include <windows.h>
  #include <malloc.h>
  
  namespace
      {
      unsigned const exception_maximum_parameters=15;
      unsigned const exception_noncontinuable=1;
  
  #if _MSC_VER==1310
      int const exception_info_offset=0x74;
  #elif ((_MSC_VER==1400 || _MSC_VER==1500) && !defined _M_X64)
      int const exception_info_offset=0x80;
  #elif ((_MSC_VER==1400 || _MSC_VER==1500) && defined _M_X64)
      int const exception_info_offset=0xE0;
  #else
      int const exception_info_offset=-1;
  #endif
  
      struct
      exception_record
          {
          unsigned long ExceptionCode;
          unsigned long ExceptionFlags;
          exception_record * ExceptionRecord;
          void * ExceptionAddress;
          unsigned long NumberParameters;
          ULONG_PTR ExceptionInformation[exception_maximum_parameters];
          };
  
      struct
      exception_pointers
          {
          exception_record * ExceptionRecord;
          void * ContextRecord;
          };
  
      unsigned const cpp_exception_code=0xE06D7363;
      unsigned const cpp_exception_magic_flag=0x19930520;
  #ifdef _M_X64
      unsigned const cpp_exception_parameter_count=4;
  #else
      unsigned const cpp_exception_parameter_count=3;
  #endif
  
      struct
      dummy_exception_type
          {
          };
  
      typedef int(dummy_exception_type::*normal_copy_constructor_ptr)(void * src);
      typedef int(dummy_exception_type::*copy_constructor_with_virtual_base_ptr)(void * src,void * dst);
      typedef void (dummy_exception_type::*destructor_ptr)();
  
      union
      cpp_copy_constructor
          {
          void * address;
          normal_copy_constructor_ptr normal_copy_constructor;
          copy_constructor_with_virtual_base_ptr copy_constructor_with_virtual_base;
          };
  
      union
      cpp_destructor
          {
          void * address;
          destructor_ptr destructor;
          };
  
      enum
      cpp_type_flags
          {
          class_is_simple_type=1,
          class_has_virtual_base=4
          };
  
      // ATTENTION: On x86 fields such as type_info and copy_constructor are really pointers
      // but on 64bit these are 32bit offsets from HINSTANCE. Hints on the 64bit handling from
      // http://blogs.msdn.com/b/oldnewthing/archive/2010/07/30/10044061.aspx .
      struct
      cpp_type_info
          {
          unsigned flags;
          int type_info;
          int this_offset;
          int vbase_descr;
          int vbase_offset;
          unsigned long size;
          int copy_constructor;
          };
  
      struct
      cpp_type_info_table
          {
          unsigned count;
          int info;
          };
  
      struct
      cpp_exception_type
          {
          unsigned flags;
          int destructor;
          int custom_handler;
          int type_info_table;
          };
  
      struct
      exception_object_deleter
          {
          cpp_exception_type const & et_;
          size_t image_base_;
  
          exception_object_deleter( cpp_exception_type const & et, size_t image_base ):
              et_(et),
              image_base_(image_base)
              {
              }
  
          void
          operator()( void * obj )
              {
              BOOST_ASSERT(obj!=0);
              dummy_exception_type* dummy_exception_ptr = static_cast<dummy_exception_type *>(obj);
              if( et_.destructor )
                  {
                  cpp_destructor destructor;
                  destructor.address = reinterpret_cast<void *>(et_.destructor + image_base_);
                  (dummy_exception_ptr->*(destructor.destructor))();
                  }
              free(obj);
              }
          };
  
      cpp_type_info const &
      get_cpp_type_info( cpp_exception_type const & et, size_t image_base )
          {
          cpp_type_info_table * const typearray = reinterpret_cast<cpp_type_info_table * const>(et.type_info_table + image_base);
          cpp_type_info * const ti = reinterpret_cast<cpp_type_info * const>(typearray->info + image_base);
          BOOST_ASSERT(ti!=0);
          return *ti;
          }
  
      void
      copy_msvc_exception( void * dst, void * src, cpp_type_info const & ti, size_t image_base )
          {
          cpp_copy_constructor copy_constructor;
          copy_constructor.address = reinterpret_cast<void *>(ti.copy_constructor + image_base);
  
          if( !(ti.flags & class_is_simple_type) && copy_constructor.normal_copy_constructor )
              {
              dummy_exception_type * dummy_exception_ptr = static_cast<dummy_exception_type *>(dst);
              if( ti.flags & class_has_virtual_base )
                  (dummy_exception_ptr->*(copy_constructor.copy_constructor_with_virtual_base))(src,dst);
              else
                  (dummy_exception_ptr->*(copy_constructor.normal_copy_constructor))(src);
              }
          else
              memmove(dst,src,ti.size);
          }
  
      boost::shared_ptr<void>
      clone_msvc_exception( void * src, cpp_exception_type const & et, size_t image_base )
          {
          BOOST_ASSERT(src!=0);
          cpp_type_info const & ti=get_cpp_type_info(et,image_base);
          if( void * dst = malloc(ti.size) )
              {
              try
                  {
                  copy_msvc_exception(dst,src,ti,image_base);
                  }
              catch(
              ... )
                  {
                  free(dst);
                  throw;
                  }
              return boost::shared_ptr<void>(dst,exception_object_deleter(et,image_base));
              }
          else
              throw std::bad_alloc();
          }
  
      class
      cloned_exception:
          public boost::exception_detail::clone_base
          {
          cloned_exception( cloned_exception const & );
          cloned_exception & operator=( cloned_exception const & );
  
          cpp_exception_type const & et_;
          size_t image_base_;
          boost::shared_ptr<void> exc_;
  
          public:
          cloned_exception( EXCEPTION_RECORD const * record ):
              et_(*reinterpret_cast<cpp_exception_type const *>(record->ExceptionInformation[2])),
              image_base_((cpp_exception_parameter_count==4) ? record->ExceptionInformation[3] : 0),
              exc_(clone_msvc_exception(reinterpret_cast<void *>(record->ExceptionInformation[1]),et_,image_base_))
              {
              }
  
          cloned_exception( void * exc, cpp_exception_type const & et, size_t image_base ):
              et_(et),
              image_base_(image_base),
              exc_(clone_msvc_exception(exc,et_,image_base))
              {
              }
  
          ~cloned_exception() BOOST_NOEXCEPT_OR_NOTHROW
              {
              }
  
          boost::exception_detail::clone_base const *
          clone() const
              {
              return new cloned_exception(exc_.get(),et_,image_base_);
              }
  
          void
          rethrow() const
              {
              cpp_type_info const & ti=get_cpp_type_info(et_,image_base_);
              void * dst = _alloca(ti.size);
              copy_msvc_exception(dst,exc_.get(),ti,image_base_);
              ULONG_PTR args[cpp_exception_parameter_count];
              args[0]=cpp_exception_magic_flag;
              args[1]=reinterpret_cast<ULONG_PTR>(dst);
              args[2]=reinterpret_cast<ULONG_PTR>(&et_);
              if (cpp_exception_parameter_count==4)
                  args[3]=image_base_;
  
              RaiseException(cpp_exception_code,EXCEPTION_NONCONTINUABLE,cpp_exception_parameter_count,args);
              }
          };
  
      bool
      is_cpp_exception( EXCEPTION_RECORD const * record )
          {
          return record && 
              (record->ExceptionCode==cpp_exception_code) &&
              (record->NumberParameters==cpp_exception_parameter_count) &&
              (record->ExceptionInformation[0]==cpp_exception_magic_flag);
          }
  
      unsigned long
      exception_cloning_filter( int & result, boost::exception_detail::clone_base const * & ptr, void * info_ )
          {
          BOOST_ASSERT(exception_info_offset>=0);
          BOOST_ASSERT(info_!=0);
          EXCEPTION_RECORD* record = static_cast<EXCEPTION_POINTERS *>(info_)->ExceptionRecord;
          if( is_cpp_exception(record) )
              {
              if( !record->ExceptionInformation[2] )
                  record = *reinterpret_cast<EXCEPTION_RECORD * *>(reinterpret_cast<char *>(_errno())+exception_info_offset);
              if( is_cpp_exception(record) && record->ExceptionInformation[2] )
                  try
                      {
                      ptr = new cloned_exception(record);
                      result = boost::exception_detail::clone_current_exception_result::success;
                      }
                  catch(
                  std::bad_alloc & )
                      {
                      result = boost::exception_detail::clone_current_exception_result::bad_alloc;
                      }
                  catch(
                  ... )
                      {
                      result = boost::exception_detail::clone_current_exception_result::bad_exception;
                      }
              }
          return EXCEPTION_EXECUTE_HANDLER;
          }
      }
  
  namespace
  boost
      {
      namespace
      exception_detail
          {
          int
          clone_current_exception_non_intrusive( clone_base const * & cloned )
              {
              BOOST_ASSERT(!cloned);
              int result = clone_current_exception_result::not_supported;
              if( exception_info_offset>=0 )
                  {
                   clone_base const * ptr=0;
                  __try
                      {
                      throw;
                      }
                  __except(exception_cloning_filter(result,ptr,GetExceptionInformation()))
                      {
                      }
                  if( result==clone_current_exception_result::success )
                      cloned=ptr;
                  }
              BOOST_ASSERT(result!=clone_current_exception_result::success || cloned);
              return result;
              }
          }
      }
  
  #else
  
  //On all other compilers, return clone_current_exception_result::not_supported.
  //On such platforms, only the intrusive enable_current_exception() cloning will work.
  
  namespace
  boost
      {
      namespace
      exception_detail
          {
          int
          clone_current_exception_non_intrusive( clone_base const * & )
              {
              return clone_current_exception_result::not_supported;
              }
          }
      }
  
  #endif
  