summaryrefslogtreecommitdiff
path: root/src/vm/eepolicy.h
blob: 9ca09bb67becc939e6a4f9b4aa4017aa699f7f54 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
//

//
// ---------------------------------------------------------------------------
// EEPolicy.h
// ---------------------------------------------------------------------------


#ifndef EEPOLICY_H_
#define EEPOLICY_H_

#include "vars.hpp"
#include "corhost.h"
#include "ceemain.h"

extern "C" UINT_PTR STDCALL GetCurrentIP();

enum StackOverflowDetector
{
    SOD_ManagedFrameHandler,
    SOD_UnmanagedFrameHandler,
    SOD_SOTolerantTransitor,
    SOD_SOIntolerantTransitor,
};

// EEPolicy maintains actions for resource failure and timeout
class EEPolicy
{
public:
    enum ThreadAbortTypes
    {
        TA_None,  // No Abort
        // Abort at a safe spot: not having any lock, not inside finally, not inside catch
        TA_Safe,
        // Do we need this one?
        TA_V1Compatible,
        // Do not run user finally, no attention to lock count
        TA_Rude
    };

    enum AppDomainUnloadTypes
    {
        ADU_Safe,
        ADU_Rude
    };

    EEPolicy ();

    HRESULT SetTimeout(EClrOperation operation, DWORD timeout);

    DWORD GetTimeout(EClrOperation operation)
    {
        LIMITED_METHOD_CONTRACT;
        _ASSERTE(static_cast<UINT>(operation) < MaxClrOperation);
        return m_Timeout[operation];
    }

    HRESULT SetActionOnTimeout(EClrOperation operation, EPolicyAction action);
    EPolicyAction GetActionOnTimeout(EClrOperation operation, Thread *pThread)
    {
        WRAPPER_NO_CONTRACT;
        _ASSERTE(static_cast<UINT>(operation) < MaxClrOperation);
        return GetFinalAction(m_ActionOnTimeout[operation], pThread);
    }

    void NotifyHostOnTimeout(EClrOperation operation, EPolicyAction action);

    HRESULT SetTimeoutAndAction(EClrOperation operation, DWORD timeout, EPolicyAction action);
    
    HRESULT SetDefaultAction(EClrOperation operation, EPolicyAction action);
    EPolicyAction GetDefaultAction(EClrOperation operation, Thread *pThread)
    {
        WRAPPER_NO_CONTRACT;
        _ASSERTE(static_cast<UINT>(operation) < MaxClrOperation);
        return GetFinalAction(m_DefaultAction[operation], pThread);
    }

    void NotifyHostOnDefaultAction(EClrOperation operation, EPolicyAction action);

    HRESULT SetActionOnFailure(EClrFailure failure, EPolicyAction action);

    // Generally GetActionOnFailure should be used so that a host can get notification.
    // But if we have notified host on the same failure, but we need to check escalation again,
    // GetActionOnFailureNoHostNotification can be used.
    EPolicyAction GetActionOnFailure(EClrFailure failure);
    EPolicyAction GetActionOnFailureNoHostNotification(EClrFailure failure);

    // get and set unhandled exception policy
    HRESULT SetUnhandledExceptionPolicy(EClrUnhandledException policy)
    {
        LIMITED_METHOD_CONTRACT;
        if (policy != eRuntimeDeterminedPolicy && policy != eHostDeterminedPolicy)
        {
            return E_INVALIDARG;
        }
        else
        {
            m_unhandledExceptionPolicy = policy;
            return S_OK;
        }
    }
    EClrUnhandledException GetUnhandledExceptionPolicy()
    {
        LIMITED_METHOD_CONTRACT;
        return m_unhandledExceptionPolicy;
    }

    static EPolicyAction DetermineResourceConstraintAction(Thread *pThread);

    static void PerformResourceConstraintAction(Thread *pThread, EPolicyAction action, UINT exitCode, BOOL haveStack);

    static void HandleOutOfMemory();

    static void HandleStackOverflow(StackOverflowDetector detector, void * pLimitFrame);

    static void HandleSoftStackOverflow(BOOL fSkipDebugger = FALSE);

    static void HandleStackOverflowAfterCatch();

    static void HandleExitProcess(ShutdownCompleteAction sca = SCA_ExitProcessWhenShutdownComplete);

    static void DECLSPEC_NORETURN HandleFatalError(UINT exitCode, UINT_PTR address, LPCWSTR pMessage=NULL, PEXCEPTION_POINTERS pExceptionInfo= NULL, LPCWSTR errorSource=NULL, LPCWSTR argExceptionString=NULL);

    static void DECLSPEC_NORETURN HandleFatalStackOverflow(EXCEPTION_POINTERS *pException, BOOL fSkipDebugger = FALSE);

    static void HandleExitProcessFromEscalation(EPolicyAction action, UINT exitCode);

    static void HandleCodeContractFailure(LPCWSTR pMessage, LPCWSTR pCondition, LPCWSTR pInnerExceptionAsString);

private:
    DWORD m_Timeout[MaxClrOperation];
    EPolicyAction m_ActionOnTimeout[MaxClrOperation];
    EPolicyAction m_DefaultAction[MaxClrOperation];
    EPolicyAction m_ActionOnFailure[MaxClrFailure];
    EClrUnhandledException m_unhandledExceptionPolicy;
    
    // TODO: Support multiple methods to set policy: hosting, config, managed api.

    // Return BOOL if action is acceptable for operation.
    BOOL IsValidActionForOperation(EClrOperation operation, EPolicyAction action);
    BOOL IsValidActionForTimeout(EClrOperation operation, EPolicyAction action);
    BOOL IsValidActionForFailure(EClrFailure failure, EPolicyAction action);
    EPolicyAction GetFinalAction(EPolicyAction action, Thread *pThread);

    static void LogFatalError(UINT exitCode, UINT_PTR address, LPCWSTR pMessage, PEXCEPTION_POINTERS pExceptionInfo, LPCWSTR errorSource, LPCWSTR argExceptionString=NULL);

    // IMPORTANT NOTE: only the following two functions should be calling ExitProcessViaShim.
    // - CorHost2::ExitProcess
    // - SafeExitProcess
    friend class CorHost2;
    friend void SafeExitProcess(UINT , BOOL , ShutdownCompleteAction);

    static void ExitProcessViaShim(UINT exitCode);
};

void InitEEPolicy();

extern BYTE g_EEPolicyInstance[];

inline EEPolicy* GetEEPolicy()
{
    return (EEPolicy*)&g_EEPolicyInstance;
}

extern void FinalizerThreadAbortOnTimeout();
extern ULONGLONG GetObjFinalizeStartTime();

//
// Use EEPOLICY_HANDLE_FATAL_ERROR when you have a situtation where the Runtime's internal state would be
// inconsistent if execution were allowed to continue. This will apply the proper host's policy for fatal
// errors. Note: this call will never return.
//
// NOTE: make sure to use the macro instead of claling EEPolicy::HandleFatalError directly. The macro grabs the IP
// of where you are calling this from, so we can log it to help when debugging these failures later.
//

// FailFast with specific error code
#define EEPOLICY_HANDLE_FATAL_ERROR(_exitcode) EEPolicy::HandleFatalError(_exitcode, GetCurrentIP());

// FailFast with specific error code and message (LPWSTR)
#define EEPOLICY_HANDLE_FATAL_ERROR_WITH_MESSAGE(_exitcode, _message) EEPolicy::HandleFatalError(_exitcode, GetCurrentIP(), _message);

// FailFast with specific error code and exception details
#define EEPOLICY_HANDLE_FATAL_ERROR_USING_EXCEPTION_INFO(_exitcode, _pExceptionInfo) EEPolicy::HandleFatalError(_exitcode, GetCurrentIP(), NULL, _pExceptionInfo);

// Failfast with specific error code, exception details, and debug info
#define EEPOLICY_HANDLE_FATAL_ERROR_USING_EXCEPTION_AND_DEBUG_INFO(_exitcode, _pExceptionInfo, _isDebug) EEPolicy::HandleFatalError(_exitcode, GetCurrentIP(), NULL, _pExceptionInfo, _isDebug);

#endif  // EEPOLICY_H_