Throw.h 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. //-------------------------------------------------------------------------------------------------------
  2. // Copyright (C) Microsoft. All rights reserved.
  3. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
  4. //-------------------------------------------------------------------------------------------------------
  5. #pragma once
  6. #ifdef STACK_BACK_TRACE
  7. class StackBackTrace;
  8. #endif
  9. namespace Js {
  10. class ScriptContext;
  11. class Throw
  12. {
  13. public:
  14. static void __declspec(noreturn) OutOfMemory();
  15. static void __declspec(noreturn) StackOverflow(ScriptContext *scriptContext, PVOID returnAddress);
  16. static void __declspec(noreturn) NotImplemented();
  17. static void __declspec(noreturn) InternalError();
  18. static void __declspec(noreturn) FatalInternalError(HRESULT hr = E_FAIL);
  19. static void __declspec(noreturn) FatalInternalErrorEx(int scenario);
  20. static void __declspec(noreturn) FatalInternalGlobalizationError();
  21. static void __declspec(noreturn) FatalProjectionError();
  22. #if ENABLE_JS_REENTRANCY_CHECK
  23. static void __declspec(noreturn) FatalJsReentrancyError();
  24. #endif
  25. #ifdef ENABLE_JS_BUILTINS
  26. static void __declspec(noreturn) FatalJsBuiltInError();
  27. #endif
  28. #if !defined(_M_IX86) && defined(_WIN32)
  29. static void XDataRegistrationError(HRESULT hr, ULONG_PTR funcStart);
  30. #endif
  31. static bool ReportAssert(__in LPCSTR fileName, uint lineNumber, __in LPCSTR error, __in LPCSTR message);
  32. static void LogAssert();
  33. #ifdef GENERATE_DUMP
  34. static int GenerateDump(PEXCEPTION_POINTERS exceptInfo, LPCWSTR filePath, int ret = EXCEPTION_CONTINUE_SEARCH, bool needLock = false);
  35. static void GenerateDump(LPCWSTR filePath, bool terminate = false, bool needLock = false);
  36. static void GenerateDumpForAssert(LPCWSTR filePath);
  37. private:
  38. static CriticalSection csGenerateDump;
  39. #ifdef STACK_BACK_TRACE
  40. THREAD_LOCAL static StackBackTrace * stackBackTrace;
  41. static const int StackToSkip = 2;
  42. static const int StackTraceDepth = 40;
  43. #endif
  44. #endif
  45. };
  46. // Info: Verify the result or throw catastrophic
  47. // Parameters: HRESULT
  48. inline void VerifyOkCatastrophic(__in HRESULT hr)
  49. {
  50. if (hr == E_OUTOFMEMORY)
  51. {
  52. Js::Throw::OutOfMemory();
  53. }
  54. else if (FAILED(hr))
  55. {
  56. Js::Throw::FatalProjectionError();
  57. }
  58. }
  59. // Info: Verify the result or throw catastrophic
  60. // Parameters: bool
  61. template<typename TCheck>
  62. inline void VerifyCatastrophic(__in TCheck result)
  63. {
  64. if (!result)
  65. {
  66. Assert(false);
  67. Js::Throw::FatalProjectionError();
  68. }
  69. }
  70. } // namespace Js
  71. #define BEGIN_TRANSLATE_TO_HRESULT(type) \
  72. {\
  73. try \
  74. { \
  75. AUTO_HANDLED_EXCEPTION_TYPE(type);
  76. #define BEGIN_TRANSLATE_TO_HRESULT_NESTED(type) \
  77. {\
  78. try \
  79. { \
  80. AUTO_NESTED_HANDLED_EXCEPTION_TYPE(type);
  81. #define BEGIN_TRANSLATE_OOM_TO_HRESULT BEGIN_TRANSLATE_TO_HRESULT(ExceptionType_OutOfMemory)
  82. #define BEGIN_TRANSLATE_OOM_TO_HRESULT_NESTED BEGIN_TRANSLATE_TO_HRESULT_NESTED(ExceptionType_OutOfMemory)
  83. #define END_TRANSLATE_OOM_TO_HRESULT(hr) \
  84. } \
  85. catch (Js::OutOfMemoryException) \
  86. { \
  87. hr = E_OUTOFMEMORY; \
  88. }\
  89. }
  90. #define END_TRANSLATE_OOM_TO_HRESULT_AND_EXCEPTION_OBJECT(hr, scriptContext, exceptionObject) \
  91. } \
  92. catch(Js::OutOfMemoryException) \
  93. { \
  94. hr = E_OUTOFMEMORY; \
  95. *exceptionObject = Js::JavascriptExceptionOperators::GetOutOfMemoryExceptionObject(scriptContext); \
  96. } \
  97. }
  98. #define BEGIN_TRANSLATE_EXCEPTION_TO_HRESULT BEGIN_TRANSLATE_TO_HRESULT((ExceptionType)(ExceptionType_OutOfMemory | ExceptionType_StackOverflow))
  99. #define BEGIN_TRANSLATE_EXCEPTION_TO_HRESULT_NESTED BEGIN_TRANSLATE_TO_HRESULT_NESTED((ExceptionType)(ExceptionType_OutOfMemory | ExceptionType_StackOverflow))
  100. #define BEGIN_TRANSLATE_EXCEPTION_AND_ERROROBJECT_TO_HRESULT BEGIN_TRANSLATE_TO_HRESULT((ExceptionType)(ExceptionType_OutOfMemory | ExceptionType_StackOverflow | ExceptionType_JavascriptException))
  101. #define BEGIN_TRANSLATE_EXCEPTION_AND_ERROROBJECT_TO_HRESULT_NESTED BEGIN_TRANSLATE_TO_HRESULT_NESTED((ExceptionType)(ExceptionType_OutOfMemory | ExceptionType_StackOverflow | ExceptionType_JavascriptException))
  102. #define END_TRANSLATE_KNOWN_EXCEPTION_TO_HRESULT(hr) \
  103. } \
  104. catch (Js::OutOfMemoryException) \
  105. { \
  106. hr = E_OUTOFMEMORY; \
  107. } \
  108. catch (Js::StackOverflowException) \
  109. { \
  110. hr = VBSERR_OutOfStack; \
  111. } \
  112. catch (Js::NotImplementedException) \
  113. { \
  114. hr = E_NOTIMPL; \
  115. } \
  116. catch (Js::ScriptAbortException) \
  117. { \
  118. hr = E_ABORT; \
  119. } \
  120. catch (Js::AsmJsParseException) \
  121. { \
  122. hr = JSERR_AsmJsCompileError; \
  123. }
  124. // This should be the inverse of END_TRANSLATE_KNOWN_EXCEPTION_TO_HRESULT, and catch all the same cases.
  125. #define THROW_KNOWN_HRESULT_EXCEPTIONS(hr, scriptContext) \
  126. if (hr == E_OUTOFMEMORY) \
  127. { \
  128. JavascriptError::ThrowOutOfMemoryError(scriptContext); \
  129. } \
  130. else if (hr == VBSERR_OutOfStack) \
  131. { \
  132. JavascriptError::ThrowStackOverflowError(scriptContext); \
  133. } \
  134. else if (hr == E_NOTIMPL) \
  135. { \
  136. throw Js::NotImplementedException(); \
  137. } \
  138. else if (hr == E_ABORT) \
  139. { \
  140. throw Js::ScriptAbortException(); \
  141. } \
  142. else if (hr == JSERR_AsmJsCompileError) \
  143. { \
  144. throw Js::AsmJsParseException(); \
  145. } \
  146. else if (FAILED(hr)) \
  147. { \
  148. /* Intended to be the inverse of E_FAIL in CATCH_UNHANDLED_EXCEPTION */ \
  149. AssertOrFailFastHR(false, hr); \
  150. }
  151. #define CATCH_UNHANDLED_EXCEPTION(hr) \
  152. catch (...) \
  153. { \
  154. AssertOrFailFastMsg(FALSE, "invalid exception thrown and didn't get handled"); \
  155. hr = E_FAIL; /* Suppress C4701 */ \
  156. } \
  157. }
  158. #define END_TRANSLATE_EXCEPTION_TO_HRESULT(hr) \
  159. END_TRANSLATE_KNOWN_EXCEPTION_TO_HRESULT(hr)\
  160. CATCH_UNHANDLED_EXCEPTION(hr)
  161. #define END_TRANSLATE_EXCEPTION_AND_ERROROBJECT_TO_HRESULT(hr) \
  162. Assert(!JsUtil::ExternalApi::IsScriptActiveOnCurrentThreadContext()); \
  163. END_TRANSLATE_KNOWN_EXCEPTION_TO_HRESULT(hr) \
  164. END_TRANSLATE_ERROROBJECT_TO_HRESULT(hr) \
  165. CATCH_UNHANDLED_EXCEPTION(hr)
  166. // Use this version if execution is in script (use rarely)
  167. #define END_TRANSLATE_EXCEPTION_AND_ERROROBJECT_TO_HRESULT_INSCRIPT(hr) \
  168. Assert(JsUtil::ExternalApi::IsScriptActiveOnCurrentThreadContext()); \
  169. END_TRANSLATE_KNOWN_EXCEPTION_TO_HRESULT(hr) \
  170. END_TRANSLATE_ERROROBJECT_TO_HRESULT_INSCRIPT(hr) \
  171. CATCH_UNHANDLED_EXCEPTION(hr)
  172. #define END_TRANSLATE_EXCEPTION_AND_ERROROBJECT_TO_HRESULT_NOASSERT(hr) \
  173. END_TRANSLATE_KNOWN_EXCEPTION_TO_HRESULT(hr) \
  174. END_TRANSLATE_ERROROBJECT_TO_HRESULT(hr) \
  175. CATCH_UNHANDLED_EXCEPTION(hr)
  176. #define END_TRANSLATE_ERROROBJECT_TO_HRESULT_EX(hr, GetRuntimeErrorFunc) \
  177. catch(const Js::JavascriptException& err) \
  178. { \
  179. Js::JavascriptExceptionObject* exceptionObject = err.GetAndClear(); \
  180. GET_RUNTIME_ERROR_IMPL(hr, GetRuntimeErrorFunc, exceptionObject); \
  181. }
  182. #define GET_RUNTIME_ERROR_IMPL(hr, GetRuntimeErrorFunc, exceptionObject) \
  183. { \
  184. Js::Var errorObject = exceptionObject->GetThrownObject(nullptr); \
  185. if (errorObject != nullptr && (Js::VarIs<Js::JavascriptError>(errorObject) || \
  186. Js::JavascriptError::IsRemoteError(errorObject))) \
  187. { \
  188. hr = GetRuntimeErrorFunc(Js::VarTo<Js::RecyclableObject>(errorObject), nullptr); \
  189. } \
  190. else if (errorObject != nullptr) \
  191. { \
  192. hr = JSERR_UncaughtException; \
  193. } \
  194. else \
  195. { \
  196. AssertMsg(errorObject == nullptr, "errorObject should be NULL"); \
  197. hr = E_OUTOFMEMORY; \
  198. } \
  199. }
  200. #define GET_RUNTIME_ERROR(hr, exceptionObject) \
  201. GET_RUNTIME_ERROR_IMPL(hr, Js::JavascriptError::GetRuntimeErrorWithScriptEnter, exceptionObject)
  202. #define END_TRANSLATE_ERROROBJECT_TO_HRESULT(hr) \
  203. END_TRANSLATE_ERROROBJECT_TO_HRESULT_EX(hr, Js::JavascriptError::GetRuntimeErrorWithScriptEnter)
  204. #define END_GET_ERROROBJECT(hr, scriptContext, exceptionObject) \
  205. catch (const Js::JavascriptException& err) \
  206. { \
  207. Js::JavascriptExceptionObject * _exceptionObject = err.GetAndClear(); \
  208. BEGIN_TRANSLATE_OOM_TO_HRESULT_NESTED \
  209. exceptionObject = _exceptionObject; \
  210. exceptionObject = exceptionObject->CloneIfStaticExceptionObject(scriptContext); \
  211. END_TRANSLATE_OOM_TO_HRESULT(hr) \
  212. }
  213. #define CATCH_STATIC_JAVASCRIPT_EXCEPTION_OBJECT(errCode) \
  214. catch (Js::OutOfMemoryException) \
  215. { \
  216. errCode = JsErrorOutOfMemory; \
  217. } catch (Js::StackOverflowException) \
  218. { \
  219. errCode = JsErrorOutOfMemory; \
  220. } \
  221. #if ENABLE_TTD
  222. #define CATCH_OTHER_EXCEPTIONS(errCode) \
  223. catch (JsrtExceptionBase& e) \
  224. { \
  225. errCode = e.GetJsErrorCode(); \
  226. } \
  227. catch (Js::ExceptionBase) \
  228. { \
  229. AssertMsg(false, "Unexpected engine exception."); \
  230. errCode = JsErrorFatal; \
  231. } \
  232. catch (TTD::TTDebuggerAbortException) \
  233. { \
  234. throw; /*don't set errcode we treat this as non-termination of the code that was executing*/ \
  235. } \
  236. catch (...) \
  237. { \
  238. AssertMsg(false, "Unexpected non-engine exception."); \
  239. errCode = JsErrorFatal; \
  240. }
  241. #else
  242. #define CATCH_OTHER_EXCEPTIONS(errCode) \
  243. catch (JsrtExceptionBase& e) \
  244. { \
  245. errCode = e.GetJsErrorCode(); \
  246. } \
  247. catch (Js::ExceptionBase) \
  248. { \
  249. AssertMsg(false, "Unexpected engine exception."); \
  250. errCode = JsErrorFatal; \
  251. } \
  252. catch (...) \
  253. { \
  254. AssertMsg(false, "Unexpected non-engine exception."); \
  255. errCode = JsErrorFatal; \
  256. }
  257. #endif
  258. // Use this version if execution is in script (use rarely)
  259. #define END_TRANSLATE_ERROROBJECT_TO_HRESULT_INSCRIPT(hr) \
  260. END_TRANSLATE_ERROROBJECT_TO_HRESULT_EX(hr, Js::JavascriptError::GetRuntimeError)
  261. #define TRANSLATE_EXCEPTION_TO_HRESULT_ENTRY(ex) \
  262. } \
  263. catch (ex) \
  264. {
  265. #define DEBUGGER_ATTACHDETACH_FATAL_ERROR_IF_FAILED(hr) if (hr != S_OK) Debugger_AttachDetach_unrecoverable_error(hr);