1// Licensed to the .NET Foundation under one or more agreements.
2// The .NET Foundation licenses this file to you under the MIT license.
3// See the LICENSE file in the project root for more information.
4//
5
6//
7// ---------------------------------------------------------------------------
8// EEPolicy.cpp
9// ---------------------------------------------------------------------------
10
11
12#include "common.h"
13#include "eepolicy.h"
14#include "corhost.h"
15#include "dbginterface.h"
16#include "eemessagebox.h"
17
18#include "eventreporter.h"
19#include "finalizerthread.h"
20#include "threadsuspend.h"
21
22#include "typestring.h"
23
24#ifndef FEATURE_PAL
25#include "dwreport.h"
26#endif // !FEATURE_PAL
27
28#include "eventtrace.h"
29#undef ExitProcess
30
31BYTE g_EEPolicyInstance[sizeof(EEPolicy)];
32
33void InitEEPolicy()
34{
35 WRAPPER_NO_CONTRACT;
36 new (g_EEPolicyInstance) EEPolicy();
37}
38
39EEPolicy::EEPolicy ()
40{
41 CONTRACTL
42 {
43 GC_NOTRIGGER;
44 NOTHROW;
45 }
46 CONTRACTL_END;
47
48 int n;
49 for (n = 0; n < MaxClrOperation; n++) {
50 m_Timeout[n] = INFINITE;
51 m_ActionOnTimeout[n] = eNoAction;
52 m_DefaultAction[n] = eNoAction;
53 }
54 m_Timeout[OPR_ProcessExit] = 40000;
55 m_ActionOnTimeout[OPR_ProcessExit] = eRudeExitProcess;
56 m_ActionOnTimeout[OPR_ThreadAbort] = eAbortThread;
57 m_ActionOnTimeout[OPR_ThreadRudeAbortInNonCriticalRegion] = eRudeAbortThread;
58 m_ActionOnTimeout[OPR_ThreadRudeAbortInCriticalRegion] = eRudeAbortThread;
59
60 m_DefaultAction[OPR_ThreadAbort] = eAbortThread;
61 m_DefaultAction[OPR_ThreadRudeAbortInNonCriticalRegion] = eRudeAbortThread;
62 m_DefaultAction[OPR_ThreadRudeAbortInCriticalRegion] = eRudeAbortThread;
63 m_DefaultAction[OPR_AppDomainUnload] = eUnloadAppDomain;
64 m_DefaultAction[OPR_AppDomainRudeUnload] = eRudeUnloadAppDomain;
65 m_DefaultAction[OPR_ProcessExit] = eExitProcess;
66 m_DefaultAction[OPR_FinalizerRun] = eNoAction;
67
68 for (n = 0; n < MaxClrFailure; n++) {
69 m_ActionOnFailure[n] = eNoAction;
70 }
71 m_ActionOnFailure[FAIL_CriticalResource] = eThrowException;
72 m_ActionOnFailure[FAIL_NonCriticalResource] = eThrowException;
73 m_ActionOnFailure[FAIL_OrphanedLock] = eNoAction;
74 m_ActionOnFailure[FAIL_FatalRuntime] = eRudeExitProcess;
75 // For CoreCLR, initialize the default action for AV processing to all
76 // all kind of code to catch AV exception. If the host wants, they can
77 // specify a different action for this.
78 m_ActionOnFailure[FAIL_AccessViolation] = eNoAction;
79 m_ActionOnFailure[FAIL_StackOverflow] = eRudeExitProcess;
80 m_ActionOnFailure[FAIL_CodeContract] = eThrowException;
81 m_unhandledExceptionPolicy = eRuntimeDeterminedPolicy;
82}
83
84BOOL EEPolicy::IsValidActionForOperation(EClrOperation operation, EPolicyAction action)
85{
86 CONTRACTL
87 {
88 GC_NOTRIGGER;
89 NOTHROW;
90 }
91 CONTRACTL_END;
92
93 switch (operation) {
94 case OPR_ThreadAbort:
95 return action >= eAbortThread &&
96 action < MaxPolicyAction;
97 case OPR_ThreadRudeAbortInNonCriticalRegion:
98 case OPR_ThreadRudeAbortInCriticalRegion:
99 return action >= eRudeAbortThread && action != eUnloadAppDomain &&
100 action < MaxPolicyAction;
101 case OPR_AppDomainUnload:
102 return action >= eUnloadAppDomain &&
103 action < MaxPolicyAction;
104 case OPR_AppDomainRudeUnload:
105 return action >= eRudeUnloadAppDomain &&
106 action < MaxPolicyAction;
107 case OPR_ProcessExit:
108 return action >= eExitProcess &&
109 action < MaxPolicyAction;
110 case OPR_FinalizerRun:
111 return action == eNoAction ||
112 (action >= eAbortThread &&
113 action < MaxPolicyAction);
114 default:
115 _ASSERT (!"Do not know valid action for this operation");
116 break;
117 }
118 return FALSE;
119}
120
121BOOL EEPolicy::IsValidActionForTimeout(EClrOperation operation, EPolicyAction action)
122{
123 CONTRACTL
124 {
125 GC_NOTRIGGER;
126 NOTHROW;
127 }
128 CONTRACTL_END;
129
130 switch (operation) {
131 case OPR_ThreadAbort:
132 return action > eAbortThread &&
133 action < MaxPolicyAction;
134 case OPR_ThreadRudeAbortInNonCriticalRegion:
135 case OPR_ThreadRudeAbortInCriticalRegion:
136 return action > eRudeUnloadAppDomain &&
137 action < MaxPolicyAction;
138 case OPR_AppDomainUnload:
139 return action > eUnloadAppDomain &&
140 action < MaxPolicyAction;
141 case OPR_AppDomainRudeUnload:
142 return action > eRudeUnloadAppDomain &&
143 action < MaxPolicyAction;
144 case OPR_ProcessExit:
145 return action > eExitProcess &&
146 action < MaxPolicyAction;
147 case OPR_FinalizerRun:
148 return action == eNoAction ||
149 (action >= eAbortThread &&
150 action < MaxPolicyAction);
151 default:
152 _ASSERT (!"Do not know valid action for this operation");
153 break;
154 }
155 return FALSE;
156}
157
158BOOL EEPolicy::IsValidActionForFailure(EClrFailure failure, EPolicyAction action)
159{
160 CONTRACTL
161 {
162 GC_NOTRIGGER;
163 NOTHROW;
164 }
165 CONTRACTL_END;
166
167 switch (failure) {
168 case FAIL_NonCriticalResource:
169 return action >= eThrowException &&
170 action < MaxPolicyAction;
171 case FAIL_CriticalResource:
172 return action >= eThrowException &&
173 action < MaxPolicyAction;
174 case FAIL_FatalRuntime:
175 return action >= eRudeExitProcess &&
176 action < MaxPolicyAction;
177 case FAIL_OrphanedLock:
178 return action >= eUnloadAppDomain &&
179 action < MaxPolicyAction;
180 case FAIL_AccessViolation:
181 // Allowed actions on failure are:
182 //
183 // eNoAction or eRudeExitProcess.
184 return ((action == eNoAction) || (action == eRudeExitProcess));
185 case FAIL_StackOverflow:
186 return action >= eRudeUnloadAppDomain &&
187 action < MaxPolicyAction;
188 case FAIL_CodeContract:
189 return action >= eThrowException &&
190 action <= eExitProcess;
191 default:
192 _ASSERTE (!"Do not know valid action for this failure");
193 break;
194 }
195
196 return FALSE;
197}
198
199HRESULT EEPolicy::SetTimeout(EClrOperation operation, DWORD timeout)
200{
201 CONTRACTL
202 {
203 MODE_ANY;
204 GC_NOTRIGGER;
205 NOTHROW;
206 }
207 CONTRACTL_END;
208
209 if (static_cast<UINT>(operation) < MaxClrOperation)
210 {
211 m_Timeout[operation] = timeout;
212 if (operation == OPR_FinalizerRun &&
213 g_fEEStarted)
214 {
215 FastInterlockOr((DWORD*)&g_FinalizerWaiterStatus, FWS_WaitInterrupt);
216 FinalizerThread::SignalFinalizationDone(FALSE);
217 }
218 return S_OK;
219}
220 else
221 {
222 return E_INVALIDARG;
223 }
224}
225
226HRESULT EEPolicy::SetActionOnTimeout(EClrOperation operation, EPolicyAction action)
227{
228 CONTRACTL
229 {
230 GC_NOTRIGGER;
231 NOTHROW;
232 }
233 CONTRACTL_END;
234
235 if (static_cast<UINT>(operation) < MaxClrOperation &&
236 IsValidActionForTimeout(operation, action))
237 {
238 m_ActionOnTimeout[operation] = action;
239 return S_OK;
240 }
241 else
242 {
243 return E_INVALIDARG;
244 }
245}
246
247EPolicyAction EEPolicy::GetFinalAction(EPolicyAction action, Thread *pThread)
248{
249 LIMITED_METHOD_CONTRACT;
250 _ASSERTE(static_cast<UINT>(action) < MaxPolicyAction);
251
252 if (action < eAbortThread || action > eFastExitProcess)
253 {
254 return action;
255 }
256
257 while(TRUE)
258 {
259 // Look at default action. If the default action is more severe,
260 // use the default action instead.
261 EPolicyAction defaultAction = action;
262 switch (action)
263 {
264 case eAbortThread:
265 defaultAction = m_DefaultAction[OPR_ThreadAbort];
266 break;
267 case eRudeAbortThread:
268 if (pThread && !pThread->HasLockInCurrentDomain())
269 {
270 defaultAction = m_DefaultAction[OPR_ThreadRudeAbortInNonCriticalRegion];
271 }
272 else
273 {
274 defaultAction = m_DefaultAction[OPR_ThreadRudeAbortInCriticalRegion];
275 }
276 break;
277 case eUnloadAppDomain:
278 defaultAction = m_DefaultAction[OPR_AppDomainUnload];
279 break;
280 case eRudeUnloadAppDomain:
281 defaultAction = m_DefaultAction[OPR_AppDomainRudeUnload];
282 break;
283 case eExitProcess:
284 case eFastExitProcess:
285 defaultAction = m_DefaultAction[OPR_ProcessExit];
286 if (defaultAction < action)
287 {
288 defaultAction = action;
289 }
290 break;
291 default:
292 break;
293 }
294 _ASSERTE(static_cast<UINT>(defaultAction) < MaxPolicyAction);
295
296 if (defaultAction == action)
297 {
298 return action;
299 }
300
301 _ASSERTE(defaultAction > action);
302 action = defaultAction;
303 }
304}
305
306// Allow setting timeout and action in one call.
307// If we decide to have atomical operation on Policy, we can use lock here
308// while SetTimeout and SetActionOnTimeout can not.
309HRESULT EEPolicy::SetTimeoutAndAction(EClrOperation operation, DWORD timeout, EPolicyAction action)
310{
311 CONTRACTL
312 {
313 GC_NOTRIGGER;
314 NOTHROW;
315 }
316 CONTRACTL_END;
317
318 if (static_cast<UINT>(operation) < MaxClrOperation &&
319 IsValidActionForTimeout(operation, action))
320 {
321 m_ActionOnTimeout[operation] = action;
322 m_Timeout[operation] = timeout;
323 if (operation == OPR_FinalizerRun &&
324 g_fEEStarted)
325 {
326 FastInterlockOr((DWORD*)&g_FinalizerWaiterStatus, FWS_WaitInterrupt);
327 FinalizerThread::SignalFinalizationDone(FALSE);
328 }
329 return S_OK;
330 }
331 else
332 {
333 return E_INVALIDARG;
334 }
335}
336
337HRESULT EEPolicy::SetDefaultAction(EClrOperation operation, EPolicyAction action)
338{
339 CONTRACTL
340 {
341 GC_NOTRIGGER;
342 NOTHROW;
343 }
344 CONTRACTL_END;
345
346 if (static_cast<UINT>(operation) < MaxClrOperation &&
347 IsValidActionForOperation(operation, action))
348 {
349 m_DefaultAction[operation] = action;
350 return S_OK;
351 }
352 else
353 {
354 return E_INVALIDARG;
355 }
356}
357
358HRESULT EEPolicy::SetActionOnFailure(EClrFailure failure, EPolicyAction action)
359{
360 CONTRACTL
361 {
362 GC_NOTRIGGER;
363 NOTHROW;
364 }
365 CONTRACTL_END;
366
367 if (static_cast<UINT>(failure) < MaxClrFailure &&
368 IsValidActionForFailure(failure, action))
369 {
370 m_ActionOnFailure[failure] = action;
371 return S_OK;
372 }
373 else
374 {
375 return E_INVALIDARG;
376 }
377}
378
379EPolicyAction EEPolicy::GetActionOnFailureNoHostNotification(EClrFailure failure)
380{
381 CONTRACTL
382 {
383 SO_TOLERANT;
384 MODE_ANY;
385 GC_NOTRIGGER;
386 NOTHROW;
387 }CONTRACTL_END;
388
389 _ASSERTE (failure < MaxClrFailure);
390 if (failure == FAIL_StackOverflow)
391 {
392 return m_ActionOnFailure[failure];
393 }
394
395 return GetFinalAction(m_ActionOnFailure[failure], GetThread());
396}
397
398EPolicyAction EEPolicy::GetActionOnFailure(EClrFailure failure)
399{
400 CONTRACTL
401 {
402 SO_TOLERANT;
403 MODE_ANY;
404 GC_NOTRIGGER;
405 NOTHROW;
406 }CONTRACTL_END;
407
408 _ASSERTE(static_cast<UINT>(failure) < MaxClrFailure);
409 if (failure == FAIL_StackOverflow)
410 {
411 return m_ActionOnFailure[failure];
412 }
413
414 EPolicyAction finalAction = GetActionOnFailureNoHostNotification(failure);
415 return finalAction;
416}
417
418
419void EEPolicy::NotifyHostOnTimeout(EClrOperation operation, EPolicyAction action)
420{
421 CONTRACTL
422 {
423 THROWS;
424 GC_NOTRIGGER;
425 MODE_ANY;
426 SO_TOLERANT;
427 }
428 CONTRACTL_END;
429
430}
431
432
433void EEPolicy::NotifyHostOnDefaultAction(EClrOperation operation, EPolicyAction action)
434{
435 CONTRACTL
436 {
437 NOTHROW;
438 GC_NOTRIGGER;
439 MODE_ANY;
440 SO_TOLERANT;
441 }
442 CONTRACTL_END;
443
444}
445
446void SafeExitProcess(UINT exitCode, BOOL fAbort = FALSE, ShutdownCompleteAction sca = SCA_ExitProcessWhenShutdownComplete)
447{
448 // The process is shutting down. No need to check SO contract.
449 SO_NOT_MAINLINE_FUNCTION;
450 STRESS_LOG2(LF_SYNC, LL_INFO10, "SafeExitProcess: exitCode = %d, fAbort = %d\n", exitCode, fAbort);
451 CONTRACTL
452 {
453 DISABLED(GC_TRIGGERS);
454 NOTHROW;
455 }
456 CONTRACTL_END;
457
458 // The runtime must be in the appropriate thread mode when we exit, so that we
459 // aren't surprised by the thread mode when our DLL_PROCESS_DETACH occurs, or when
460 // other DLLs call Release() on us in their detach [dangerous!], etc.
461 GCX_PREEMP_NO_DTOR();
462
463 FastInterlockExchange((LONG*)&g_fForbidEnterEE, TRUE);
464
465 ProcessEventForHost(Event_ClrDisabled, NULL);
466
467 // Note that for free and retail builds StressLog must also be enabled
468 if (g_pConfig && g_pConfig->StressLog())
469 {
470 if (CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_BreakOnBadExit))
471 {
472 // Workaround for aspnet
473 PathString wszFilename;
474 bool bShouldAssert = true;
475 if (WszGetModuleFileName(NULL, wszFilename))
476 {
477 wszFilename.LowerCase();
478
479 if (wcsstr(wszFilename, W("aspnet_compiler")))
480 {
481 bShouldAssert = false;
482 }
483 }
484
485 unsigned goodExit = CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_SuccessExit);
486 if (bShouldAssert && exitCode != goodExit)
487 {
488 _ASSERTE(!"Bad Exit value");
489 FAULT_NOT_FATAL(); // if we OOM we can simply give up
490 SetErrorMode(0); // Insure that we actually cause the messsage box to pop.
491 EEMessageBoxCatastrophic(IDS_EE_ERRORMESSAGETEMPLATE, IDS_EE_ERRORTITLE, exitCode, W("BreakOnBadExit: returning bad exit code"));
492 }
493 }
494 }
495
496 // If we call ExitProcess, other threads will be torn down
497 // so we don't get to debug their state. Stop this!
498#ifdef _DEBUG
499 if (_DbgBreakCount)
500 _ASSERTE(!"In SafeExitProcess: An assert was hit on some other thread");
501#endif
502
503 // Turn off exception processing, because if some other random DLL has a
504 // fault in DLL_PROCESS_DETACH, we could get called for exception handling.
505 // Since we've turned off part of the runtime, we can't, for instance,
506 // properly execute the GC that handling an exception might trigger.
507 g_fNoExceptions = true;
508 LOG((LF_EH, LL_INFO10, "SafeExitProcess: turning off exceptions\n"));
509
510 if (sca == SCA_ExitProcessWhenShutdownComplete)
511 {
512 // disabled because if we fault in this code path we will trigger our
513 // Watson code via EntryPointFilter which is THROWS (see Dev11 317016)
514 CONTRACT_VIOLATION(ThrowsViolation);
515
516#ifdef FEATURE_PAL
517 if (fAbort)
518 {
519 TerminateProcess(GetCurrentProcess(), exitCode);
520 }
521#endif
522
523 EEPolicy::ExitProcessViaShim(exitCode);
524 }
525}
526
527// This is a helper to exit the process after coordinating with the shim. It is used by
528// SafeExitProcess above, as well as from CorHost2::ExitProcess when we know that we must
529// exit the process without doing further work to shutdown this runtime. This first attempts
530// to call back to the Shim to shutdown any other runtimes within the process.
531//
532// IMPORTANT NOTE: exercise extreme caution when adding new calls to this method. It is highly
533// likely that you want to call SafeExitProcess, or EEPolicy::HandleExitProcess instead of this.
534// This function only exists to factor some common code out of the methods mentioned above.
535
536//static
537void EEPolicy::ExitProcessViaShim(UINT exitCode)
538{
539 LIMITED_METHOD_CONTRACT;
540
541 // We must call back to the Shim in order to exit the process, as this may be just one
542 // runtime in a process with many. We need to give the other runtimes a chance to exit
543 // cleanly. If we can't make the call, or if the call fails for some reason, then we
544 // simply exit the process here, which is rude to the others, but the best we can do.
545
546 ExitProcess(exitCode);
547}
548
549
550//---------------------------------------------------------------------------------------
551// DisableRuntime disables this runtime, suspending all managed execution and preventing
552// threads from entering the runtime. This will cause the caller to block forever as well
553// unless sca is SCA_ReturnWhenShutdownComplete.
554//---------------------------------------------------------------------------------------
555void DisableRuntime(ShutdownCompleteAction sca)
556{
557 CONTRACTL
558 {
559 DISABLED(GC_TRIGGERS);
560 NOTHROW;
561 }
562 CONTRACTL_END;
563
564 FastInterlockExchange((LONG*)&g_fForbidEnterEE, TRUE);
565
566 if (!g_fSuspendOnShutdown)
567 {
568 if (!IsGCThread())
569 {
570 if (ThreadStore::HoldingThreadStore(GetThread()))
571 {
572 ThreadSuspend::UnlockThreadStore();
573 }
574 ThreadSuspend::SuspendEE(ThreadSuspend::SUSPEND_FOR_SHUTDOWN);
575 }
576
577 if (!g_fSuspendOnShutdown)
578 {
579 ThreadStore::TrapReturningThreads(TRUE);
580 g_fSuspendOnShutdown = TRUE;
581 ClrFlsSetThreadType(ThreadType_Shutdown);
582 }
583
584 // Don't restart runtime. CLR is disabled.
585 }
586
587 GCX_PREEMP_NO_DTOR();
588
589 ProcessEventForHost(Event_ClrDisabled, NULL);
590 ClrFlsClearThreadType(ThreadType_Shutdown);
591
592 if (g_pDebugInterface != NULL)
593 {
594 g_pDebugInterface->DisableDebugger();
595 }
596
597 if (sca == SCA_ExitProcessWhenShutdownComplete)
598 {
599 __SwitchToThread(INFINITE, CALLER_LIMITS_SPINNING);
600 _ASSERTE (!"Should not reach here");
601 SafeExitProcess(0);
602 }
603}
604
605//---------------------------------------------------------------------------------------
606// HandleExitProcessHelper is used to shutdown the runtime as specified by the given
607// action, then to exit the process. Note, however, that the process will not exit if
608// sca is SCA_ReturnWhenShutdownComplete. In that case, this method will simply return after
609// performing the shutdown actions.
610//---------------------------------------------------------------------------------------
611
612// If g_fFastExitProcess is 0, normal shutdown
613// If g_fFastExitProcess is 1, fast shutdown. Only doing log.
614// If g_fFastExitProcess is 2, do not run EEShutDown.
615DWORD g_fFastExitProcess = 0;
616
617extern void STDMETHODCALLTYPE EEShutDown(BOOL fIsDllUnloading);
618
619static void HandleExitProcessHelper(EPolicyAction action, UINT exitCode, ShutdownCompleteAction sca)
620{
621 WRAPPER_NO_CONTRACT;
622
623 switch (action) {
624 case eFastExitProcess:
625 g_fFastExitProcess = 1;
626 case eExitProcess:
627 if (g_fEEStarted)
628 {
629 EEShutDown(FALSE);
630 }
631 if (exitCode == 0)
632 {
633 exitCode = GetLatchedExitCode();
634 }
635 SafeExitProcess(exitCode, FALSE, sca);
636 break;
637 case eRudeExitProcess:
638 g_fFastExitProcess = 2;
639 SafeExitProcess(exitCode, TRUE, sca);
640 break;
641 case eDisableRuntime:
642 DisableRuntime(sca);
643 break;
644 default:
645 _ASSERTE (!"Invalid policy");
646 break;
647 }
648}
649
650
651EPolicyAction EEPolicy::DetermineResourceConstraintAction(Thread *pThread)
652{
653 CONTRACTL
654 {
655 NOTHROW;
656 GC_NOTRIGGER;
657 SO_TOLERANT;
658 MODE_ANY;
659 }
660 CONTRACTL_END;
661
662 EPolicyAction action;
663 if (pThread->HasLockInCurrentDomain()) {
664 action = GetEEPolicy()->GetActionOnFailure(FAIL_CriticalResource);
665 }
666 else
667 action = GetEEPolicy()->GetActionOnFailure(FAIL_NonCriticalResource);
668
669 AppDomain *pDomain = GetAppDomain();
670 // If it is default domain, we can not unload the appdomain
671 if (pDomain == SystemDomain::System()->DefaultDomain() &&
672 (action == eUnloadAppDomain || action == eRudeUnloadAppDomain))
673 {
674 action = eThrowException;
675 }
676 // If the current thread is AD unload helper thread, it should not block itself.
677 else if (pThread->HasThreadStateNC(Thread::TSNC_ADUnloadHelper) &&
678 action < eExitProcess)
679 {
680 action = eThrowException;
681 }
682 return action;
683}
684
685void EEPolicy::PerformResourceConstraintAction(Thread *pThread, EPolicyAction action, UINT exitCode, BOOL haveStack)
686 {
687 WRAPPER_NO_CONTRACT;
688
689 _ASSERTE(GetAppDomain() != NULL);
690
691 switch (action) {
692 case eThrowException:
693 // Caller is going to rethrow.
694 return;
695 break;
696 case eAbortThread:
697 pThread->UserAbort(Thread::TAR_Thread, TA_Safe, GetEEPolicy()->GetTimeout(OPR_ThreadAbort), Thread::UAC_Normal);
698 break;
699 case eRudeAbortThread:
700 pThread->UserAbort(Thread::TAR_Thread, TA_Rude, GetEEPolicy()->GetTimeout(OPR_ThreadAbort), Thread::UAC_Normal);
701 break;
702 case eExitProcess:
703 case eFastExitProcess:
704 case eRudeExitProcess:
705 case eDisableRuntime:
706 HandleExitProcessFromEscalation(action, exitCode);
707 break;
708 default:
709 _ASSERTE (!"Invalid policy");
710 break;
711 }
712}
713
714void EEPolicy::HandleOutOfMemory()
715{
716 WRAPPER_NO_CONTRACT;
717
718 _ASSERTE (g_pOutOfMemoryExceptionClass);
719
720 Thread *pThread = GetThread();
721 _ASSERTE (pThread);
722
723 EPolicyAction action = DetermineResourceConstraintAction(pThread);
724
725 // Check if we are executing in the context of a Constrained Execution Region.
726 if (action != eThrowException && Thread::IsExecutingWithinCer())
727 {
728 // Hitting OOM in a CER region should throw the OOM without regard to the escalation policy
729 // since the CER author has declared they are hardened against such failures. That's
730 // the whole point of CERs, to denote regions where code knows exactly how to deal with
731 // failures in an attempt to minimize the need for rollback or recycling.
732 return;
733 }
734
735 PerformResourceConstraintAction(pThread, action, HOST_E_EXITPROCESS_OUTOFMEMORY, TRUE);
736}
737
738#ifdef FEATURE_STACK_PROBE
739//---------------------------------------------------------------------------------------
740//
741// IsSOTolerant - Is the current thread in SO Tolerant region?
742//
743// Arguments:
744// pLimitFrame: the limit of search for frames
745//
746// Return Value:
747// TRUE if in SO tolerant region.
748// FALSE if in SO intolerant region.
749//
750// Note:
751// We walk our frame chain to decide. If HelperMethodFrame is seen first, we are in tolerant
752// region. If EnterSOIntolerantCodeFrame is seen first, we are in intolerant region.
753//
754BOOL Thread::IsSOTolerant(void * pLimitFrame)
755{
756 LIMITED_METHOD_CONTRACT;
757
758 Frame *pFrame = GetFrame();
759 void* pSOIntolerantMarker = ClrFlsGetValue(TlsIdx_SOIntolerantTransitionHandler);
760 if (pSOIntolerantMarker == FRAME_TOP)
761 {
762 // We have not set a marker for intolerant transition yet.
763 return TRUE;
764 }
765 while (pFrame != FRAME_TOP && pFrame < pLimitFrame)
766 {
767 Frame::ETransitionType type = pFrame->GetTransitionType();
768 if (pFrame > pSOIntolerantMarker)
769 {
770 return FALSE;
771 }
772 else if (type == Frame::TT_M2U || type == Frame::TT_InternalCall ||
773 // We can not call HelperMethodFrame::GetFunction on SO since the call
774 // may need to call into host. This is why we check for TT_InternalCall first.
775 pFrame->GetFunction() != NULL)
776 {
777 return TRUE;
778 }
779 pFrame = pFrame->Next();
780 }
781
782 if (pFrame == FRAME_TOP)
783 // We walked to the end of chain, but the thread has one IntolerantMarker on stack decided from
784 // the check above while loop.
785 return FALSE;
786 else
787 return TRUE;
788}
789
790#endif
791
792//---------------------------------------------------------------------------------------
793//
794// EEPolicy::HandleStackOverflow - Handle stack overflow according to policy
795//
796// Arguments:
797// detector:
798// pLimitFrame: the limit of search for frames in order to decide if in SO tolerant
799//
800// Return Value:
801// None.
802//
803// How is stack overflow handled?
804// If stack overflows in non-hosted case, we terminate the process.
805// For hosted case with escalation policy
806// 1. If stack overflows in managed code, or in VM before switching to SO intolerant region, and the GC mode is Cooperative
807// the domain is rudely unloaded, or the process is terminated if the current domain is default domain.
808// a. This action is done through BEGIN_SO_TOLERANT_CODE if there is one.
809// b. If there is not this macro on the stack, we mark the domain being unload requested, and when the thread
810// dies or is recycled, we finish the AD unload.
811// 2. If stack overflows in SO tolerant region, but the GC mode is Preemptive, the process is killed in vector handler, or our
812// managed exception handler (COMPlusFrameHandler or ProcessCLRException).
813// 3. If stack overflows in SO intolerant region, the process is killed as soon as the exception is seen by our vector handler, or
814// our managed exception handler.
815//
816// If SO Probing code is disabled (by FEATURE_STACK_PROBE not defined) then the process
817// is terminated if there is StackOverflow as all clr code will be considered SO Intolerant.
818void EEPolicy::HandleStackOverflow(StackOverflowDetector detector, void * pLimitFrame)
819{
820 WRAPPER_NO_CONTRACT;
821
822 STRESS_LOG0(LF_EH, LL_INFO100, "In EEPolicy::HandleStackOverflow\n");
823
824 Thread *pThread = GetThread();
825
826 if (pThread == NULL)
827 {
828 //_ASSERTE (detector != SOD_ManagedFrameHandler);
829 // ProcessSOEventForHost(NULL, FALSE);
830
831 // For security reason, it is not safe to continue execution if stack overflow happens
832 // unless a host tells us to do something different.
833 // EEPolicy::HandleFatalStackOverflow(NULL);
834 return;
835 }
836
837#ifdef FEATURE_STACK_PROBE
838
839 // We only process SO once at
840 // 1. VectoredExceptionHandler if SO in mscorwks
841 // 2. managed exception handler
842 // 3. SO_Tolerant transition handler
843 if (pThread->HasThreadStateNC(Thread::TSNC_SOWorkNeeded) &&
844 detector != SOD_UnmanagedFrameHandler)
845 {
846 return;
847 }
848#endif
849
850#ifdef FEATURE_STACK_PROBE
851 BOOL fInSoTolerant = pThread->IsSOTolerant(pLimitFrame);
852#else
853 BOOL fInSoTolerant = false;
854#endif
855
856 EXCEPTION_POINTERS exceptionInfo;
857 GetCurrentExceptionPointers(&exceptionInfo);
858
859 _ASSERTE(exceptionInfo.ExceptionRecord);
860
861#ifdef FEATURE_STACK_PROBE
862 DWORD exceptionCode = exceptionInfo.ExceptionRecord->ExceptionCode;
863
864 AppDomain *pCurrentDomain = ::GetAppDomain();
865 BOOL fInDefaultDomain = (pCurrentDomain == SystemDomain::System()->DefaultDomain());
866 BOOL fInCLR = IsIPInModule(g_pMSCorEE, (PCODE)GetIP(exceptionInfo.ContextRecord));
867
868 if (exceptionCode == EXCEPTION_SOFTSO)
869 {
870 // Our probe detects a thread does not have enough stack. But we have not trashed the process
871 // state yet.
872 fInSoTolerant = TRUE;
873 }
874 else
875 {
876 _ASSERTE (exceptionCode == STATUS_STACK_OVERFLOW);
877
878 switch (detector)
879 {
880 case SOD_ManagedFrameHandler:
881 if (!pThread->PreemptiveGCDisabled() && !fInCLR && fInSoTolerant)
882 {
883 // Managed exception handler detects SO, but the thread is in preemptive GC mode,
884 // and the IP is outside CLR. This means we are inside a PINVOKE call.
885 fInSoTolerant = FALSE;
886 }
887 break;
888
889 case SOD_UnmanagedFrameHandler:
890 break;
891
892 case SOD_SOIntolerantTransitor:
893 fInSoTolerant = FALSE;
894 break;
895
896 case SOD_SOTolerantTransitor:
897 if (!fInCLR)
898 {
899 // If SO happens outside of CLR, and it is not detected by managed frame handler,
900 // it is fatal
901 fInSoTolerant = FALSE;
902 }
903 break;
904
905 default:
906 _ASSERTE(!"should not get here");
907 }
908
909 if (fInDefaultDomain)
910 {
911 // StackOverflow in default domain is fatal
912 fInSoTolerant = FALSE;
913 }
914 }
915
916#endif // FEATURE_STACK_PROBE
917
918 ProcessSOEventForHost(&exceptionInfo, fInSoTolerant);
919
920#ifdef FEATURE_STACK_PROBE
921 if (!CLRHosted() || GetEEPolicy()->GetActionOnFailure(FAIL_StackOverflow) != eRudeUnloadAppDomain)
922 {
923 // For security reason, it is not safe to continue execution if stack overflow happens
924 // unless a host tells us to do something different.
925 EEPolicy::HandleFatalStackOverflow(&exceptionInfo);
926 }
927#endif
928
929 if (!fInSoTolerant)
930 {
931 EEPolicy::HandleFatalStackOverflow(&exceptionInfo);
932 }
933#ifdef FEATURE_STACK_PROBE
934 else
935 {
936 // EnableADUnloadWorker is SO_Intolerant.
937 // But here we know that if we have only one page, we will only update states of the Domain.
938 CONTRACT_VIOLATION(SOToleranceViolation);
939
940 pThread->PrepareThreadForSOWork();
941
942 pThread->MarkThreadForAbort(
943 (Thread::ThreadAbortRequester)(Thread::TAR_Thread|Thread::TAR_StackOverflow),
944 EEPolicy::TA_Rude);
945
946 pThread->SetSOWorkNeeded();
947 }
948#endif
949}
950
951
952// We provide WatsonLastChance with a SO exception record. The ExceptionAddress is set to 0
953// here. This ExceptionPointers struct is handed off to the debugger as is. A copy of this struct
954// is made before invoking Watson and the ExceptionAddress is set by inspecting the stack. Note
955// that the ExceptionContext member is unused and so it's ok to set it to NULL.
956static EXCEPTION_RECORD g_SOExceptionRecord = {
957 STATUS_STACK_OVERFLOW, // ExceptionCode
958 0, // ExceptionFlags
959 NULL, // ExceptionRecord
960 0, // ExceptionAddress
961 0, // NumberOfParameters
962 {} }; // ExceptionInformation
963
964EXCEPTION_POINTERS g_SOExceptionPointers = {&g_SOExceptionRecord, NULL};
965
966#ifdef FEATURE_STACK_PROBE
967// This function may be called on a thread before debugger is notified of the thread, like in
968// ManagedThreadBase_DispatchMiddle. Currently we can not notify managed debugger, because
969// RS requires that notification is sent first.
970void EEPolicy::HandleSoftStackOverflow(BOOL fSkipDebugger)
971{
972 WRAPPER_NO_CONTRACT;
973
974 // If we trigger a SO while handling the soft stack overflow,
975 // we'll rip the process
976 BEGIN_SO_INTOLERANT_CODE_NOPROBE;
977
978 AppDomain *pCurrentDomain = ::GetAppDomain();
979
980 if (GetEEPolicy()->GetActionOnFailure(FAIL_StackOverflow) != eRudeUnloadAppDomain ||
981 pCurrentDomain == SystemDomain::System()->DefaultDomain())
982 {
983 // We may not be able to build a context on stack
984 ProcessSOEventForHost(NULL, FALSE);
985
986
987 EEPolicy::HandleFatalStackOverflow(&g_SOExceptionPointers, fSkipDebugger);
988 }
989 //else if (pCurrentDomain == SystemDomain::System()->DefaultDomain())
990 //{
991 // We hit soft SO in Default domain, but default domain can not be unloaded.
992 // Soft SO can happen in default domain, eg. GetResourceString, or EnsureGrantSetSerialized.
993 // So the caller is going to throw a managed exception.
994 // RaiseException(EXCEPTION_SOFTSO, 0, 0, NULL);
995 //}
996 else
997 {
998 Thread* pThread = GetThread();
999
1000 // We are leaving VM boundary, either entering managed code, or entering
1001 // non-VM unmanaged code.
1002 // We should not throw internal C++ exception. Instead we throw an exception
1003 // with EXCEPTION_SOFTSO code.
1004 RaiseException(EXCEPTION_SOFTSO, 0, 0, NULL);
1005 }
1006
1007 END_SO_INTOLERANT_CODE_NOPROBE;
1008
1009}
1010
1011void EEPolicy::HandleStackOverflowAfterCatch()
1012{
1013 CONTRACTL
1014 {
1015 NOTHROW;
1016 GC_NOTRIGGER;
1017 SO_TOLERANT;
1018 MODE_ANY;
1019 }
1020 CONTRACTL_END;
1021
1022#ifdef STACK_GUARDS_DEBUG
1023 BaseStackGuard::RestoreCurrentGuard(FALSE);
1024#endif
1025 Thread *pThread = GetThread();
1026 pThread->RestoreGuardPage();
1027 pThread->FinishSOWork();
1028}
1029#endif
1030
1031
1032//---------------------------------------------------------------------------------------
1033// HandleExitProcess is used to shutdown the runtime, based on policy previously set,
1034// then to exit the process. Note, however, that the process will not exit if
1035// sca is SCA_ReturnWhenShutdownComplete. In that case, this method will simply return after
1036// performing the shutdown actions.
1037//---------------------------------------------------------------------------------------
1038void EEPolicy::HandleExitProcess(ShutdownCompleteAction sca)
1039{
1040 WRAPPER_NO_CONTRACT;
1041
1042 STRESS_LOG0(LF_EH, LL_INFO100, "In EEPolicy::HandleExitProcess\n");
1043
1044 EPolicyAction action = GetEEPolicy()->GetDefaultAction(OPR_ProcessExit, NULL);
1045 GetEEPolicy()->NotifyHostOnDefaultAction(OPR_ProcessExit,action);
1046 HandleExitProcessHelper(action, 0, sca);
1047}
1048
1049StackWalkAction LogCallstackForLogCallback(
1050 CrawlFrame *pCF, //
1051 VOID* pData // Caller's private data
1052)
1053{
1054 CONTRACTL
1055 {
1056 THROWS;
1057 GC_TRIGGERS;
1058 SO_INTOLERANT;
1059 MODE_ANY;
1060 }
1061 CONTRACTL_END;
1062
1063 SmallStackSString *pWordAt = ((SmallStackSString*)pData);
1064
1065 MethodDesc *pMD = pCF->GetFunction();
1066 _ASSERTE(pMD != NULL);
1067
1068 StackSString str;
1069 str = *pWordAt;
1070
1071 TypeString::AppendMethodInternal(str, pMD, TypeString::FormatNamespace|TypeString::FormatFullInst|TypeString::FormatSignature);
1072 PrintToStdErrW(str.GetUnicode());
1073 PrintToStdErrA("\n");
1074
1075 return SWA_CONTINUE;
1076}
1077
1078//---------------------------------------------------------------------------------------
1079//
1080// A worker to save managed stack trace.
1081//
1082// Arguments:
1083// None
1084//
1085// Return Value:
1086// None
1087//
1088inline void LogCallstackForLogWorker()
1089{
1090 Thread* pThread = GetThread();
1091 _ASSERTE (pThread);
1092
1093 SmallStackSString WordAt;
1094
1095 if (!WordAt.LoadResource(CCompRC::Optional, IDS_ER_WORDAT))
1096 {
1097 WordAt.Set(W(" at"));
1098 }
1099 else
1100 {
1101 WordAt.Insert(WordAt.Begin(), W(" "));
1102 }
1103 WordAt += W(" ");
1104
1105 pThread->StackWalkFrames(&LogCallstackForLogCallback, &WordAt, QUICKUNWIND | FUNCTIONSONLY);
1106}
1107
1108//---------------------------------------------------------------------------------------
1109//
1110// Generate an EventLog entry for unhandled exception.
1111//
1112// Arguments:
1113// pExceptionInfo - Exception information
1114//
1115// Return Value:
1116// None
1117//
1118inline void DoLogForFailFastException(LPCWSTR pszMessage, PEXCEPTION_POINTERS pExceptionInfo, LPCWSTR errorSource, LPCWSTR argExceptionString)
1119{
1120 WRAPPER_NO_CONTRACT;
1121
1122 Thread *pThread = GetThread();
1123 EX_TRY
1124 {
1125 if (errorSource == NULL)
1126 {
1127 PrintToStdErrA("FailFast:");
1128 }
1129 else
1130 {
1131 PrintToStdErrW((WCHAR*)errorSource);
1132 }
1133
1134 PrintToStdErrA("\n");
1135 PrintToStdErrW((WCHAR*)pszMessage);
1136 PrintToStdErrA("\n");
1137
1138 if (pThread && errorSource == NULL)
1139 {
1140 PrintToStdErrA("\n");
1141 LogCallstackForLogWorker();
1142
1143 if (argExceptionString != NULL) {
1144 PrintToStdErrA("\n");
1145 PrintToStdErrA("Exception details:");
1146 PrintToStdErrA("\n");
1147 PrintToStdErrW((WCHAR*)argExceptionString);
1148 PrintToStdErrA("\n");
1149 }
1150 }
1151 }
1152 EX_CATCH
1153 {
1154 }
1155 EX_END_CATCH(SwallowAllExceptions)
1156}
1157
1158//This starts FALSE and then converts to true if HandleFatalError has ever been called by a GC thread
1159BOOL g_fFatalErrorOccuredOnGCThread = FALSE;
1160//
1161// Log an error to the event log if possible, then throw up a dialog box.
1162//
1163
1164void EEPolicy::LogFatalError(UINT exitCode, UINT_PTR address, LPCWSTR pszMessage, PEXCEPTION_POINTERS pExceptionInfo, LPCWSTR errorSource, LPCWSTR argExceptionString)
1165{
1166 STATIC_CONTRACT_NOTHROW;
1167 STATIC_CONTRACT_GC_TRIGGERS;
1168 STATIC_CONTRACT_MODE_ANY;
1169
1170 _ASSERTE(pExceptionInfo != NULL);
1171
1172 // Log FailFast exception to StdErr
1173 if (exitCode == (UINT)COR_E_FAILFAST)
1174 {
1175 DoLogForFailFastException(pszMessage, pExceptionInfo, errorSource, argExceptionString);
1176 }
1177
1178 if(ETW_EVENT_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PRIVATE_PROVIDER_Context, FailFast))
1179 {
1180 // Fire an ETW FailFast event
1181 FireEtwFailFast(pszMessage,
1182 (const PVOID)address,
1183 ((pExceptionInfo && pExceptionInfo->ExceptionRecord) ? pExceptionInfo->ExceptionRecord->ExceptionCode : 0),
1184 exitCode,
1185 GetClrInstanceId());
1186 }
1187
1188#ifndef FEATURE_PAL
1189 // Write an event log entry. We do allocate some resources here (spread between the stack and maybe the heap for longer
1190 // messages), so it's possible for the event write to fail. If needs be we can use a more elaborate scheme here in the future
1191 // (maybe trying multiple approaches and backing off on failure, falling back on a limited size static buffer as a last
1192 // resort). In all likelihood the Win32 event reporting mechanism requires resources though, so it's not clear how much
1193 // effort we should put into this without knowing the benefit we'd receive.
1194 EX_TRY
1195 {
1196 if (ShouldLogInEventLog())
1197 {
1198 // If the exit code is COR_E_FAILFAST then the fatal error was raised by managed code and the address argument points to a
1199 // unicode message buffer rather than a faulting EIP.
1200 EventReporter::EventReporterType failureType = EventReporter::ERT_UnmanagedFailFast;
1201 if (exitCode == (UINT)COR_E_FAILFAST)
1202 failureType = EventReporter::ERT_ManagedFailFast;
1203 else if (exitCode == (UINT)COR_E_CODECONTRACTFAILED)
1204 failureType = EventReporter::ERT_CodeContractFailed;
1205 EventReporter reporter(failureType);
1206 StackSString s(argExceptionString);
1207
1208 if ((exitCode == (UINT)COR_E_FAILFAST) || (exitCode == (UINT)COR_E_CODECONTRACTFAILED) || (exitCode == (UINT)CLR_E_GC_OOM))
1209 {
1210 if (pszMessage)
1211 {
1212 reporter.AddDescription((WCHAR*)pszMessage);
1213 }
1214
1215 if (argExceptionString)
1216 {
1217 reporter.AddFailFastStackTrace(s);
1218 }
1219
1220 if (exitCode != (UINT)CLR_E_GC_OOM)
1221 LogCallstackForEventReporter(reporter);
1222 }
1223 else
1224 {
1225 // Fetch the localized Fatal Execution Engine Error text or fall back on a hardcoded variant if things get dire.
1226 InlineSString<80> ssMessage;
1227 InlineSString<80> ssErrorFormat;
1228 if(!ssErrorFormat.LoadResource(CCompRC::Optional, IDS_ER_UNMANAGEDFAILFASTMSG ))
1229 ssErrorFormat.Set(W("at IP %1 (%2) with exit code %3."));
1230 SmallStackSString addressString;
1231 addressString.Printf(W("%p"), pExceptionInfo? (UINT_PTR)pExceptionInfo->ExceptionRecord->ExceptionAddress : address);
1232
1233 // We should always have the reference to the runtime's instance
1234 _ASSERTE(g_pMSCorEE != NULL);
1235
1236 // Setup the string to contain the runtime's base address. Thus, when customers report FEEE with just
1237 // the event log entry containing this string, we can use the absolute and base addresses to determine
1238 // where the fault happened inside the runtime.
1239 SmallStackSString runtimeBaseAddressString;
1240 runtimeBaseAddressString.Printf(W("%p"), g_pMSCorEE);
1241
1242 SmallStackSString exitCodeString;
1243 exitCodeString.Printf(W("%x"), exitCode);
1244
1245 // Format the string
1246 ssMessage.FormatMessage(FORMAT_MESSAGE_FROM_STRING, (LPCWSTR)ssErrorFormat, 0, 0, addressString, runtimeBaseAddressString,
1247 exitCodeString);
1248 reporter.AddDescription(ssMessage);
1249 }
1250
1251 reporter.Report();
1252 }
1253 }
1254 EX_CATCH
1255 {
1256 }
1257 EX_END_CATCH(SwallowAllExceptions)
1258#endif // !FEATURE_PAL
1259
1260#ifdef _DEBUG
1261 // If we're native-only (Win32) debugging this process, we'd love to break now.
1262 // However, we should not do this because a managed debugger attached to a
1263 // SxS runtime also appears to be a native debugger. Unfortunately, the managed
1264 // debugger won't handle any native event from another runtime, which means this
1265 // breakpoint would go unhandled and terminate the process. Instead, we will let
1266 // the process continue so at least the fatal error is logged rather than abrupt
1267 // termination.
1268 //
1269 // This behavior can still be overridden if the right config value is set.
1270 if (IsDebuggerPresent())
1271 {
1272 bool fBreak = (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_DbgOOBinFEEE) != 0);
1273
1274 if (fBreak)
1275 {
1276 DebugBreak();
1277 }
1278 }
1279#endif // _DEBUG
1280
1281 // We're here logging a fatal error. If the policy is to then do anything other than
1282 // disable the runtime (ie, if the policy is to terminate the runtime), we should give
1283 // Watson an opportunity to capture an error report.
1284 // Presumably, hosts that are sophisticated enough to disable the runtime are also cognizant
1285 // of how they want to handle fatal errors in the runtime, including whether they want
1286 // to capture Watson information (for which they are responsible).
1287 if (GetEEPolicy()->GetActionOnFailureNoHostNotification(FAIL_FatalRuntime) != eDisableRuntime)
1288 {
1289#ifdef DEBUGGING_SUPPORTED
1290 //Give a managed debugger a chance if this fatal error is on a managed thread.
1291 Thread *pThread = GetThread();
1292
1293 if (pThread && !g_fFatalErrorOccuredOnGCThread)
1294 {
1295 GCX_COOP();
1296
1297 OBJECTHANDLE ohException = NULL;
1298
1299 if (exitCode == (UINT)COR_E_STACKOVERFLOW)
1300 {
1301 // If we're going down because of stack overflow, go ahead and use the preallocated SO exception.
1302 ohException = CLRException::GetPreallocatedStackOverflowExceptionHandle();
1303 }
1304 else
1305 {
1306 // Though we would like to remove the usage of ExecutionEngineException in any manner,
1307 // we cannot. Its okay to use it in the case below since the process is terminating
1308 // and this will serve as an exception object for debugger.
1309 ohException = CLRException::GetPreallocatedExecutionEngineExceptionHandle();
1310 }
1311
1312 // Preallocated exception handles can be null if FailFast is invoked before LoadBaseSystemClasses
1313 // (in SystemDomain::Init) finished. See Dev10 Bug 677432 for the detail.
1314 if (ohException != NULL)
1315 {
1316 // for fail-fast, if there's a LTO available then use that as the inner exception object
1317 // for the FEEE we'll be reporting. this can help the Watson back-end to generate better
1318 // buckets for apps that call Environment.FailFast() and supply an exception object.
1319 OBJECTREF lto = pThread->LastThrownObject();
1320
1321 if (exitCode == static_cast<UINT>(COR_E_FAILFAST) && lto != NULL)
1322 {
1323 EXCEPTIONREF curEx = (EXCEPTIONREF)ObjectFromHandle(ohException);
1324 curEx->SetInnerException(lto);
1325 }
1326 pThread->SetLastThrownObject(ObjectFromHandle(ohException), TRUE);
1327 }
1328
1329 // If a managed debugger is already attached, and if that debugger is thinking it might be inclined to
1330 // try to intercept this excepiton, then tell it that's not possible.
1331 if (pThread->IsExceptionInProgress())
1332 {
1333 pThread->GetExceptionState()->GetFlags()->SetDebuggerInterceptNotPossible();
1334 }
1335 }
1336
1337 if (EXCEPTION_CONTINUE_EXECUTION == WatsonLastChance(pThread, pExceptionInfo, TypeOfReportedError::FatalError))
1338 {
1339 LOG((LF_EH, LL_INFO100, "EEPolicy::LogFatalError: debugger ==> EXCEPTION_CONTINUE_EXECUTION\n"));
1340 _ASSERTE(!"Debugger should not have returned ContinueExecution");
1341 }
1342#endif // DEBUGGING_SUPPORTED
1343 }
1344}
1345
1346void DisplayStackOverflowException()
1347{
1348 LIMITED_METHOD_CONTRACT;
1349 PrintToStdErrA("\n");
1350
1351 PrintToStdErrA("Process is terminating due to StackOverflowException.\n");
1352}
1353
1354void DECLSPEC_NORETURN EEPolicy::HandleFatalStackOverflow(EXCEPTION_POINTERS *pExceptionInfo, BOOL fSkipDebugger)
1355{
1356 // This is fatal error. We do not care about SO mode any more.
1357 // All of the code from here on out is robust to any failures in any API's that are called.
1358 CONTRACT_VIOLATION(GCViolation | ModeViolation | SOToleranceViolation | FaultNotFatal | TakesLockViolation);
1359
1360 WRAPPER_NO_CONTRACT;
1361
1362 STRESS_LOG0(LF_EH, LL_INFO100, "In EEPolicy::HandleFatalStackOverflow\n");
1363
1364 DisplayStackOverflowException();
1365
1366 if(ETW_EVENT_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PRIVATE_PROVIDER_Context, FailFast))
1367 {
1368 // Fire an ETW FailFast event
1369 FireEtwFailFast(W("StackOverflowException"),
1370 (const PVOID)((pExceptionInfo && pExceptionInfo->ContextRecord) ? GetIP(pExceptionInfo->ContextRecord) : 0),
1371 ((pExceptionInfo && pExceptionInfo->ExceptionRecord) ? pExceptionInfo->ExceptionRecord->ExceptionCode : 0),
1372 COR_E_STACKOVERFLOW,
1373 GetClrInstanceId());
1374 }
1375
1376 if (!fSkipDebugger)
1377 {
1378 Thread *pThread = GetThread();
1379 BOOL fTreatAsNativeUnhandledException = FALSE;
1380 if (pThread)
1381 {
1382 GCX_COOP();
1383 // If we had a SO before preallocated exception objects are initialized, we will AV here. This can happen
1384 // during the initialization of SystemDomain during EEStartup. Thus, setup the SO throwable only if its not
1385 // NULL.
1386 //
1387 // When WatsonLastChance (WLC) is invoked below, it treats this case as UnhandledException. If there is no
1388 // managed exception object available, we should treat this case as NativeUnhandledException. This aligns
1389 // well with the fact that there cannot be a managed debugger attached at this point that will require
1390 // LastChanceManagedException notification to be delivered. Also, this is the same as how
1391 // we treat an unhandled exception as NativeUnhandled when throwable is not available.
1392 OBJECTHANDLE ohSO = CLRException::GetPreallocatedStackOverflowExceptionHandle();
1393 if (ohSO != NULL)
1394 {
1395 pThread->SafeSetThrowables(ObjectFromHandle(ohSO)
1396 DEBUG_ARG(ThreadExceptionState::STEC_CurrentTrackerEqualNullOkHackForFatalStackOverflow),
1397 TRUE);
1398 }
1399 else
1400 {
1401 // We dont have a throwable - treat this as native unhandled exception
1402 fTreatAsNativeUnhandledException = TRUE;
1403 }
1404 }
1405 FrameWithCookie<FaultingExceptionFrame> fef;
1406#if defined(WIN64EXCEPTIONS)
1407 *((&fef)->GetGSCookiePtr()) = GetProcessGSCookie();
1408#endif // WIN64EXCEPTIONS
1409 if (pExceptionInfo && pExceptionInfo->ContextRecord)
1410 {
1411 GCX_COOP();
1412 fef.InitAndLink(pExceptionInfo->ContextRecord);
1413 }
1414
1415#ifndef FEATURE_PAL
1416 if (IsWatsonEnabled() && (g_pDebugInterface != NULL))
1417 {
1418 _ASSERTE(pExceptionInfo != NULL);
1419
1420 ResetWatsonBucketsParams param;
1421 param.m_pThread = pThread;
1422 param.pExceptionRecord = pExceptionInfo->ExceptionRecord;
1423 g_pDebugInterface->RequestFavor(ResetWatsonBucketsFavorWorker, reinterpret_cast<void *>(&param));
1424 }
1425#endif // !FEATURE_PAL
1426
1427 WatsonLastChance(pThread, pExceptionInfo,
1428 (fTreatAsNativeUnhandledException == FALSE)? TypeOfReportedError::UnhandledException: TypeOfReportedError::NativeThreadUnhandledException);
1429 }
1430
1431 TerminateProcess(GetCurrentProcess(), COR_E_STACKOVERFLOW);
1432 UNREACHABLE();
1433}
1434
1435
1436
1437
1438void DECLSPEC_NORETURN EEPolicy::HandleFatalError(UINT exitCode, UINT_PTR address, LPCWSTR pszMessage /* = NULL */, PEXCEPTION_POINTERS pExceptionInfo /* = NULL */, LPCWSTR errorSource /* = NULL */, LPCWSTR argExceptionString /* = NULL */)
1439{
1440 WRAPPER_NO_CONTRACT;
1441
1442 // All of the code from here on out is robust to any failures in any API's that are called.
1443 FAULT_NOT_FATAL();
1444
1445 EXCEPTION_RECORD exceptionRecord;
1446 EXCEPTION_POINTERS exceptionPointers;
1447 CONTEXT context;
1448
1449 if (pExceptionInfo == NULL)
1450 {
1451 ZeroMemory(&exceptionPointers, sizeof(exceptionPointers));
1452 ZeroMemory(&exceptionRecord, sizeof(exceptionRecord));
1453 ZeroMemory(&context, sizeof(context));
1454
1455 context.ContextFlags = CONTEXT_CONTROL;
1456 ClrCaptureContext(&context);
1457
1458 exceptionRecord.ExceptionCode = exitCode;
1459 exceptionRecord.ExceptionAddress = reinterpret_cast< PVOID >(address);
1460
1461 exceptionPointers.ExceptionRecord = &exceptionRecord;
1462 exceptionPointers.ContextRecord = &context;
1463 pExceptionInfo = &exceptionPointers;
1464 }
1465
1466 // All of the code from here on out is allowed to trigger a GC, even if we're in a no-trigger region. We're
1467 // ripping the process down due to a fatal error... our invariants are already gone.
1468 {
1469 // This is fatal error. We do not care about SO mode any more.
1470 // All of the code from here on out is robust to any failures in any API's that are called.
1471 CONTRACT_VIOLATION(GCViolation | ModeViolation | SOToleranceViolation | FaultNotFatal | TakesLockViolation);
1472
1473
1474 // Setting g_fFatalErrorOccuredOnGCThread allows code to avoid attempting to make GC mode transitions which could
1475 // block indefinately if the fatal error occured during the GC.
1476 if (IsGCSpecialThread() && GCHeapUtilities::IsGCInProgress())
1477 {
1478 g_fFatalErrorOccuredOnGCThread = TRUE;
1479 }
1480
1481 // ThreadStore lock needs to be released before continuing with the FatalError handling should
1482 // because debugger is going to take CrstDebuggerMutex, whose lock level is higher than that of
1483 // CrstThreadStore. It should be safe to release the lock since execution will not be resumed
1484 // after fatal errors.
1485 if (ThreadStore::HoldingThreadStore(GetThread()))
1486 {
1487 ThreadSuspend::UnlockThreadStore();
1488 }
1489
1490 g_fFastExitProcess = 2;
1491
1492 STRESS_LOG0(LF_CORDB,LL_INFO100, "D::HFE: About to call LogFatalError\n");
1493 switch (GetEEPolicy()->GetActionOnFailure(FAIL_FatalRuntime))
1494 {
1495 case eRudeExitProcess:
1496 LogFatalError(exitCode, address, pszMessage, pExceptionInfo, errorSource, argExceptionString);
1497 SafeExitProcess(exitCode, TRUE);
1498 break;
1499 case eDisableRuntime:
1500 LogFatalError(exitCode, address, pszMessage, pExceptionInfo, errorSource, argExceptionString);
1501 DisableRuntime(SCA_ExitProcessWhenShutdownComplete);
1502 break;
1503 default:
1504 _ASSERTE(!"Invalid action for FAIL_FatalRuntime");
1505 break;
1506 }
1507 }
1508
1509 UNREACHABLE();
1510}
1511
1512void EEPolicy::HandleExitProcessFromEscalation(EPolicyAction action, UINT exitCode)
1513{
1514 WRAPPER_NO_CONTRACT;
1515 CONTRACT_VIOLATION(GCViolation);
1516
1517 _ASSERTE (action >= eExitProcess);
1518 // If policy for ExitProcess is not default action, i.e. ExitProcess, we will use it.
1519 // Otherwise overwrite it with passing arg action;
1520 EPolicyAction todo = GetEEPolicy()->GetDefaultAction(OPR_ProcessExit, NULL);
1521 if (todo == eExitProcess)
1522 {
1523 todo = action;
1524 }
1525 GetEEPolicy()->NotifyHostOnDefaultAction(OPR_ProcessExit,todo);
1526
1527 HandleExitProcessHelper(todo, exitCode, SCA_ExitProcessWhenShutdownComplete);
1528}
1529
1530void EEPolicy::HandleCodeContractFailure(LPCWSTR pMessage, LPCWSTR pCondition, LPCWSTR pInnerExceptionAsString)
1531{
1532 WRAPPER_NO_CONTRACT;
1533
1534 EEPolicy* pPolicy = GetEEPolicy();
1535 // GetActionOnFailure will notify the host for us.
1536 EPolicyAction action = pPolicy->GetActionOnFailure(FAIL_CodeContract);
1537 Thread* pThread = GetThread();
1538 AppDomain* pCurrentDomain = ::GetAppDomain();
1539
1540 switch(action) {
1541 case eThrowException:
1542 // Let managed code throw a ContractException (it's easier to pass the right parameters to the constructor).
1543 break;
1544 case eAbortThread:
1545 pThread->UserAbort(Thread::TAR_Thread, TA_Safe, GetEEPolicy()->GetTimeout(OPR_ThreadAbort), Thread::UAC_Normal);
1546 break;
1547 case eRudeAbortThread:
1548 pThread->UserAbort(Thread::TAR_Thread, TA_Rude, GetEEPolicy()->GetTimeout(OPR_ThreadAbort), Thread::UAC_Normal);
1549 break;
1550 case eExitProcess: // Merged w/ default case
1551 default:
1552 _ASSERTE(action == eExitProcess);
1553 // Since we have no exception object, make sure
1554 // UE tracker is clean so that RetrieveManagedBucketParameters
1555 // does not take any bucket details.
1556#ifndef FEATURE_PAL
1557 pThread->GetExceptionState()->GetUEWatsonBucketTracker()->ClearWatsonBucketDetails();
1558#endif // !FEATURE_PAL
1559 pPolicy->HandleFatalError(COR_E_CODECONTRACTFAILED, NULL, pMessage);
1560 break;
1561 }
1562}
1563
1564