53-exception_pointer_msvc.patch 9.4 KB

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