53-exception_pointer_msvc.patch 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  1. diff --git a/src/support/runtime/exception_pointer_msvc.ipp b/src/support/runtime/exception_pointer_msvc.ipp
  2. index b87742b..43ac8ca 100644
  3. --- a/src/support/runtime/exception_pointer_msvc.ipp
  4. +++ b/src/support/runtime/exception_pointer_msvc.ipp
  5. @@ -7,61 +7,226 @@
  6. //
  7. //===----------------------------------------------------------------------===//
  8. -#include <stdio.h>
  9. -#include <stdlib.h>
  10. -
  11. -_LIBCPP_CRT_FUNC void __cdecl __ExceptionPtrCreate(void*);
  12. -_LIBCPP_CRT_FUNC void __cdecl __ExceptionPtrDestroy(void*);
  13. -_LIBCPP_CRT_FUNC void __cdecl __ExceptionPtrCopy(void*, const void*);
  14. -_LIBCPP_CRT_FUNC void __cdecl __ExceptionPtrAssign(void*, const void*);
  15. -_LIBCPP_CRT_FUNC bool __cdecl __ExceptionPtrCompare(const void*, const void*);
  16. -_LIBCPP_CRT_FUNC bool __cdecl __ExceptionPtrToBool(const void*);
  17. -_LIBCPP_CRT_FUNC void __cdecl __ExceptionPtrSwap(void*, void*);
  18. -_LIBCPP_CRT_FUNC void __cdecl __ExceptionPtrCurrentException(void*);
  19. -[[noreturn]] _LIBCPP_CRT_FUNC void __cdecl __ExceptionPtrRethrow(const void*);
  20. -_LIBCPP_CRT_FUNC void __cdecl __ExceptionPtrCopyException(void*, const void*, const void*);
  21. +#include <atomic>
  22. +#include <cstdint>
  23. +#include <cstring>
  24. +#include <malloc.h>
  25. +#include <windows.h> // For RtlPcToFileHeader function
  26. +
  27. +struct EHCatchableType {
  28. + uint32_t properties;
  29. + int32_t type_info;
  30. + uint32_t non_virtual_adjustment;
  31. + uint32_t offset_to_virtual_base_ptr;
  32. + uint32_t virtual_base_table_index;
  33. + uint32_t size;
  34. + int32_t copy_function;
  35. +};
  36. +
  37. +struct EHCatchableTypeArray {
  38. + uint32_t catchable_types;
  39. + // It is variable size but we only need the first element of this array
  40. + int32_t array_of_catchable_types[1];
  41. +};
  42. +
  43. +struct EHThrowInfo {
  44. + uint32_t attributes;
  45. + int32_t unwind;
  46. + int32_t forward_compat;
  47. + int32_t catchable_type_array;
  48. +};
  49. +
  50. +struct EHParameters {
  51. + uint32_t magic_number;
  52. + void* exception_object;
  53. + EHThrowInfo* throw_info;
  54. +#ifdef _M_AMD64
  55. + uintptr_t throw_image_base;
  56. +#endif
  57. +};
  58. +
  59. +struct EHExceptionRecord {
  60. + uint32_t exception_code;
  61. + uint32_t exception_flags;
  62. + void* exception_record;
  63. + void* exception_address;
  64. + uint32_t number_of_parameters;
  65. + EHParameters parameters;
  66. +};
  67. +
  68. +// defined in vcruntime<ver>.dll
  69. +extern "C" EHExceptionRecord** __current_exception();
  70. +
  71. +// This is internal compiler definition for MSVC but not for clang.
  72. +// We use our own EHThrowInfo because _ThrowInfo doesn't match actual
  73. +// compiler-generated structures in 64-bit mode.
  74. +#ifdef __clang__
  75. +struct _ThrowInfo;
  76. +// defined in vcruntime<ver>.dll
  77. +extern "C" _LIBCPP_NORETURN void __stdcall _CxxThrowException(void* __exc, _ThrowInfo* __throw_info);
  78. +#endif
  79. +
  80. +namespace {
  81. +struct ExceptionPtr {
  82. + void* exception_object;
  83. + const EHThrowInfo* throw_info;
  84. + std::atomic<size_t> counter;
  85. +#ifdef _M_AMD64
  86. + PVOID image_base;
  87. +#endif
  88. + template <class T>
  89. + T convert(int32_t offset) {
  90. +#ifdef _M_AMD64
  91. + uintptr_t value = reinterpret_cast<uintptr_t>(image_base) + static_cast<uintptr_t>(offset);
  92. +#else
  93. + uintptr_t value = static_cast<uintptr_t>(offset);
  94. +#endif
  95. + T res;
  96. + static_assert(sizeof(value) == sizeof(res), "Can only convert to pointers or pointers to member functions");
  97. + memcpy(&res, &value, sizeof(value));
  98. + return res;
  99. + }
  100. +
  101. + void copy(void* dst, const void* src, const EHCatchableType* exc_type) {
  102. + struct Temp {};
  103. + constexpr uint32_t virtual_base = 4;
  104. + if (exc_type->copy_function == 0) {
  105. + memcpy(dst, src, exc_type->size);
  106. + } else if (exc_type->properties & virtual_base) {
  107. + auto copy_constructor = convert<void (Temp::*)(const void*, int)>(exc_type->copy_function);
  108. + ((Temp*)dst->*copy_constructor)(src, 1);
  109. + } else {
  110. + auto copy_constructor = convert<void (Temp::*)(const void*)>(exc_type->copy_function);
  111. + ((Temp*)dst->*copy_constructor)(src);
  112. + }
  113. + }
  114. +
  115. + EHCatchableType* exception_type() {
  116. + return convert<EHCatchableType*>(
  117. + convert<EHCatchableTypeArray*>(throw_info->catchable_type_array)->array_of_catchable_types[0]);
  118. + }
  119. +
  120. + ExceptionPtr(const void* exception_object_, const EHThrowInfo* throw_info_)
  121. + : exception_object(nullptr), throw_info(throw_info_), counter(1) {
  122. +#ifdef _M_AMD64
  123. + RtlPcToFileHeader(reinterpret_cast<PVOID>(const_cast<EHThrowInfo*>(throw_info)), &image_base);
  124. +#endif
  125. + EHCatchableType* exc_type = exception_type();
  126. + this->exception_object = malloc(exc_type->size);
  127. + if (this->exception_object == nullptr) {
  128. + throw std::bad_alloc();
  129. + }
  130. + copy(exception_object, exception_object_, exc_type);
  131. + }
  132. +
  133. + ~ExceptionPtr() {
  134. + if (throw_info->unwind && exception_object) {
  135. + struct Temp {};
  136. + auto destructor = convert<void (Temp::*)()>(throw_info->unwind);
  137. + ((Temp*)exception_object->*destructor)();
  138. + }
  139. + free(exception_object);
  140. + }
  141. +
  142. + // _bad_alloc_storage must be initialized before bad_alloc, so we declare and define it first.
  143. + static std::bad_alloc _bad_alloc_storage;
  144. + static ExceptionPtr bad_alloc;
  145. + // static ExceptionPtr bad_exception;
  146. +};
  147. +
  148. +#ifdef __clang__
  149. +# pragma clang diagnostic push
  150. +# pragma clang diagnostic ignored "-Waddress-of-temporary"
  151. +#endif
  152. +
  153. +std::bad_alloc ExceptionPtr::_bad_alloc_storage;
  154. +
  155. +ExceptionPtr
  156. + ExceptionPtr::bad_alloc(&ExceptionPtr::_bad_alloc_storage,
  157. + reinterpret_cast<const EHThrowInfo*>(__GetExceptionInfo(ExceptionPtr::_bad_alloc_storage)));
  158. +
  159. +/* ExceptionPtr
  160. +ExceptionPtr::bad_exception(&std::bad_exception(),
  161. + reinterpret_cast<const EHThrowInfo*>(
  162. + __GetExceptionInfo(std::bad_exception()))); */
  163. +
  164. +#ifdef __clang__
  165. +# pragma clang diagnostic pop
  166. +#endif
  167. +
  168. +} // namespace
  169. namespace std {
  170. -exception_ptr::exception_ptr() noexcept { __ExceptionPtrCreate(this); }
  171. -exception_ptr::exception_ptr(nullptr_t) noexcept { __ExceptionPtrCreate(this); }
  172. -
  173. -exception_ptr::exception_ptr(const exception_ptr& __other) noexcept { __ExceptionPtrCopy(this, &__other); }
  174. -exception_ptr& exception_ptr::operator=(const exception_ptr& __other) noexcept {
  175. - __ExceptionPtrAssign(this, &__other);
  176. - return *this;
  177. +exception_ptr::exception_ptr(const exception_ptr& __other) noexcept : __ptr_(__other.__ptr_) {
  178. + if (__ptr_) {
  179. + reinterpret_cast<ExceptionPtr*>(__ptr_)->counter.fetch_add(1);
  180. + }
  181. }
  182. -exception_ptr& exception_ptr::operator=(nullptr_t) noexcept {
  183. - exception_ptr dummy;
  184. - __ExceptionPtrAssign(this, &dummy);
  185. +exception_ptr& exception_ptr::operator=(const exception_ptr& __other) noexcept {
  186. + auto before = __ptr_;
  187. + __ptr_ = __other.__ptr_;
  188. + if (__ptr_) {
  189. + reinterpret_cast<ExceptionPtr*>(__ptr_)->counter.fetch_add(1);
  190. + }
  191. + if (before) {
  192. + if (reinterpret_cast<ExceptionPtr*>(before)->counter.fetch_sub(1) == 1) {
  193. + delete reinterpret_cast<ExceptionPtr*>(before);
  194. + }
  195. + }
  196. return *this;
  197. }
  198. -exception_ptr::~exception_ptr() noexcept { __ExceptionPtrDestroy(this); }
  199. -
  200. -exception_ptr::operator bool() const noexcept { return __ExceptionPtrToBool(this); }
  201. -
  202. -bool operator==(const exception_ptr& __x, const exception_ptr& __y) noexcept {
  203. - return __ExceptionPtrCompare(&__x, &__y);
  204. +exception_ptr::~exception_ptr() noexcept {
  205. + if (__ptr_) {
  206. + if (reinterpret_cast<ExceptionPtr*>(__ptr_)->counter.fetch_sub(1) == 1) {
  207. + delete reinterpret_cast<ExceptionPtr*>(__ptr_);
  208. + }
  209. + }
  210. }
  211. -void swap(exception_ptr& lhs, exception_ptr& rhs) noexcept { __ExceptionPtrSwap(&rhs, &lhs); }
  212. -
  213. -exception_ptr __copy_exception_ptr(void* __except, const void* __ptr) {
  214. - exception_ptr __ret = nullptr;
  215. - if (__ptr)
  216. - __ExceptionPtrCopyException(&__ret, __except, __ptr);
  217. - return __ret;
  218. +exception_ptr __copy_exception_ptr(void* exception_object, const void* throw_info) {
  219. + ExceptionPtr* ptr;
  220. + try {
  221. + ptr = new ExceptionPtr(exception_object, reinterpret_cast<const EHThrowInfo*>(throw_info));
  222. + } catch (const std::bad_alloc&) {
  223. + ptr = &ExceptionPtr::bad_alloc;
  224. + ptr->counter.fetch_add(1);
  225. + } catch (...) {
  226. + // ptr = &ExceptionPtr::bad_exception;
  227. + // ptr->counter.fetch_add(1);
  228. + std::terminate();
  229. + }
  230. + exception_ptr res;
  231. + memcpy(&res, &ptr, sizeof(ptr));
  232. + return res;
  233. }
  234. exception_ptr current_exception() noexcept {
  235. - exception_ptr __ret;
  236. - __ExceptionPtrCurrentException(&__ret);
  237. - return __ret;
  238. + EHExceptionRecord** record = __current_exception();
  239. + if (*record && !std::uncaught_exception()) {
  240. + return __copy_exception_ptr((*record)->parameters.exception_object, (*record)->parameters.throw_info);
  241. + }
  242. + return exception_ptr();
  243. }
  244. -_LIBCPP_NORETURN void rethrow_exception(exception_ptr p) { __ExceptionPtrRethrow(&p); }
  245. +_LIBCPP_NORETURN void rethrow_exception(exception_ptr p) {
  246. + if (!p) {
  247. + throw std::bad_exception();
  248. + }
  249. + ExceptionPtr* exc_ptr = reinterpret_cast<ExceptionPtr*>(p.__ptr_);
  250. + EHCatchableType* exc_type = exc_ptr->exception_type();
  251. + // _CxxThrowException doesn't call free on exception object so we must
  252. + // allocate it on the stack.
  253. + void* dst = _alloca(exc_type->size);
  254. + exc_ptr->copy(dst, exc_ptr->exception_object, exc_type);
  255. + auto throw_info = reinterpret_cast<_ThrowInfo*>(const_cast<EHThrowInfo*>(exc_ptr->throw_info));
  256. + // For some reason clang doesn't call p destructor during unwinding.
  257. + // So we must clear it ourselves.
  258. + p = nullptr;
  259. + _CxxThrowException(dst, throw_info);
  260. +}
  261. nested_exception::nested_exception() noexcept : __ptr_(current_exception()) {}