1//
2// Copyright (c) Microsoft. All rights reserved.
3// Licensed under the MIT license. See LICENSE file in the project root for full license information.
4//
5
6#include "standardpch.h"
7#include "errorhandling.h"
8#include "logging.h"
9#include "runtimedetails.h"
10
11void MSC_ONLY(__declspec(noreturn)) ThrowException(DWORD exceptionCode)
12{
13 RaiseException(exceptionCode, 0, 0, nullptr);
14}
15
16// Allocating memory here seems moderately dangerous: we'll probably leak like a sieve...
17void MSC_ONLY(__declspec(noreturn)) ThrowException(DWORD exceptionCode, va_list args, const char* message)
18{
19 char* buffer = new char[8192];
20 ULONG_PTR* ptr = new ULONG_PTR();
21 *ptr = (ULONG_PTR)buffer;
22 _vsnprintf_s(buffer, 8192, 8191, message, args);
23
24 RaiseException(exceptionCode, 0, 1, ptr);
25}
26
27void MSC_ONLY(__declspec(noreturn)) ThrowException(DWORD exceptionCode, const char* msg, ...)
28{
29 va_list ap;
30 va_start(ap, msg);
31 ThrowException(exceptionCode, ap, msg);
32}
33
34SpmiException::SpmiException(PEXCEPTION_POINTERS exp) : exCode(exp->ExceptionRecord->ExceptionCode)
35{
36 exMessage =
37 (exp->ExceptionRecord->NumberParameters != 1) ? nullptr : (char*)exp->ExceptionRecord->ExceptionInformation[0];
38}
39
40SpmiException::SpmiException(DWORD exceptionCode, char* exceptionMessage)
41 : exCode(exceptionCode), exMessage(exceptionMessage)
42{
43}
44
45#if 0
46SpmiException::~SpmiException()
47{
48 delete[] exMessage;
49 exMessage = nullptr;
50}
51#endif
52
53char* SpmiException::GetExceptionMessage()
54{
55 return exMessage;
56}
57
58void SpmiException::ShowAndDeleteMessage()
59{
60 if (exMessage != nullptr)
61 {
62 LogError("Exception thrown: %s", exMessage);
63 delete[] exMessage;
64 exMessage = nullptr;
65 }
66 else
67 {
68 LogError("Unexpected exception was thrown.");
69 }
70}
71
72void SpmiException::DeleteMessage()
73{
74 delete[] exMessage;
75 exMessage = nullptr;
76}
77
78DWORD SpmiException::GetCode()
79{
80 return exCode;
81}
82
83// This filter function executes the handler only for EXCEPTIONCODE_MC, otherwise it continues the handler search.
84LONG FilterSuperPMIExceptions_CatchMC(PEXCEPTION_POINTERS pExceptionPointers, LPVOID lpvParam)
85{
86 return (pExceptionPointers->ExceptionRecord->ExceptionCode == EXCEPTIONCODE_MC) ? EXCEPTION_EXECUTE_HANDLER
87 : EXCEPTION_CONTINUE_SEARCH;
88}
89
90// This filter function captures the exception pointers and continues searching.
91LONG FilterSuperPMIExceptions_CaptureExceptionAndContinue(PEXCEPTION_POINTERS pExceptionPointers, LPVOID lpvParam)
92{
93 FilterSuperPMIExceptionsParam_CaptureException* pSPMIEParam =
94 (FilterSuperPMIExceptionsParam_CaptureException*)lpvParam;
95 pSPMIEParam->exceptionPointers = *pExceptionPointers; // Capture the exception pointers for use later
96 pSPMIEParam->exceptionCode = pSPMIEParam->exceptionPointers.ExceptionRecord->ExceptionCode;
97 return EXCEPTION_CONTINUE_SEARCH;
98}
99
100LONG FilterSuperPMIExceptions_CaptureExceptionAndStop(PEXCEPTION_POINTERS pExceptionPointers, LPVOID lpvParam)
101{
102 FilterSuperPMIExceptionsParam_CaptureException* pSPMIEParam =
103 (FilterSuperPMIExceptionsParam_CaptureException*)lpvParam;
104 pSPMIEParam->exceptionPointers = *pExceptionPointers; // Capture the exception pointers for use later
105 pSPMIEParam->exceptionCode = pSPMIEParam->exceptionPointers.ExceptionRecord->ExceptionCode;
106 return EXCEPTION_EXECUTE_HANDLER;
107}
108
109bool IsSuperPMIException(unsigned code)
110{
111 switch (code)
112 {
113 case EXCEPTIONCODE_MC:
114 case EXCEPTIONCODE_LWM:
115 case EXCEPTIONCODE_CALLUTILS:
116 case EXCEPTIONCODE_TYPEUTILS:
117 case EXCEPTIONCODE_ASSERT:
118 return true;
119 default:
120 if ((EXCEPTIONCODE_DebugBreakorAV <= code) && (code < EXCEPTIONCODE_DebugBreakorAV_MAX))
121 {
122 return true;
123 }
124 return false;
125 }
126}
127
128// This filter function executes the handler only for non-SuperPMI generated exceptions, otherwise it continues the
129// handler search. This allows for SuperPMI-thrown exceptions to pass through the JIT and be caught by the outer
130// SuperPMI handler.
131LONG FilterSuperPMIExceptions_CatchNonSuperPMIException(PEXCEPTION_POINTERS pExceptionPointers, LPVOID lpvParam)
132{
133 return !IsSuperPMIException(pExceptionPointers->ExceptionRecord->ExceptionCode);
134}
135
136bool RunWithErrorTrap(void (*function)(void*), void* param)
137{
138 bool success = true;
139
140 struct TrapParam
141 {
142 void (*function)(void*);
143 void* param;
144 } trapParam;
145 trapParam.function = function;
146 trapParam.param = param;
147
148 PAL_TRY(TrapParam*, pTrapParam, &trapParam)
149 {
150 pTrapParam->function(pTrapParam->param);
151 }
152 PAL_EXCEPT_FILTER(FilterSuperPMIExceptions_CatchNonSuperPMIException)
153 {
154 success = false;
155 }
156 PAL_ENDTRY
157
158 return success;
159}
160