Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 10 additions & 32 deletions src/libraries/System.Private.CoreLib/src/System/AppContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -82,50 +82,28 @@ public static void SetData(string name, object? data)
internal static event EventHandler<FirstChanceExceptionEventArgs>? FirstChanceException;
#pragma warning restore CS0067

private static ulong s_crashingThreadId;

#if NATIVEAOT
[System.Runtime.RuntimeExport("OnUnhandledException")]
#endif
internal static void OnUnhandledException(object e)
{
ulong currentThreadId = Thread.CurrentOSThreadId;
ulong previousCrashingThreadId = Interlocked.CompareExchange(ref s_crashingThreadId, currentThreadId, 0);
if (previousCrashingThreadId == 0)
{
#if NATIVEAOT
RuntimeExceptionHelpers.SerializeCrashInfo(System.Runtime.RhFailFastReason.UnhandledException, (e as Exception)?.Message, e as Exception);
RuntimeExceptionHelpers.SerializeCrashInfo(System.Runtime.RhFailFastReason.UnhandledException, (e as Exception)?.Message, e as Exception);
#endif
if (UnhandledException is UnhandledExceptionEventHandler handlers)
if (UnhandledException is UnhandledExceptionEventHandler handlers)
{
UnhandledExceptionEventArgs args = new(e, isTerminating: true);
foreach (UnhandledExceptionEventHandler handler in Delegate.EnumerateInvocationList(handlers))
{
UnhandledExceptionEventArgs args = new(e, isTerminating: true);
foreach (UnhandledExceptionEventHandler handler in Delegate.EnumerateInvocationList(handlers))
try
{
handler(/* AppDomain */ null!, args);
}
catch
{
try
{
handler(/* AppDomain */ null!, args);
}
catch
{
}
}
}
}
else
{
if (s_crashingThreadId == previousCrashingThreadId)
{
Environment.FailFast("OnUnhandledException called recursively");
}

// If we are already in the process of handling an unhandled
// exception, we do not want to raise the event again. We wait
// here while the other thread raises the unhandled exception.
// Waiting is important because it is possible upon returning, this thread
// could call some rude abort method that would terminate the process
// before the other thread finishes raising the unhandled exception.
Thread.Sleep(-1);
}
}

internal static void OnProcessExit()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System;
using System.Runtime.CompilerServices;
using System.Runtime.ExceptionServices;
using TestLibrary;
using Xunit;
Expand All @@ -20,14 +19,7 @@ public HandlerRegistration(UnhandledExceptionEventHandler handler)
public void Dispose()
{
AppDomain.CurrentDomain.UnhandledException -= _handler;

// See usage of s_crashingThreadId in the ExceptionHandling class.
// This is to ensure that the static field is reset after the test.
GetCrashingThreadId(null) = 0;
}

[UnsafeAccessor(UnsafeAccessorKind.StaticField, Name = "s_crashingThreadId")]
private static extern ref ulong GetCrashingThreadId([UnsafeAccessorType("System.AppContext")]object? obj);
}

[ThreadStatic]
Expand Down
Loading