From e5e673eecd309f3e7c2ec7c3c7acee30413df946 Mon Sep 17 00:00:00 2001 From: Aaron R Robinson Date: Wed, 24 Sep 2025 14:12:06 -0700 Subject: [PATCH] Revert unhandled exception logic to prevent multiple calls. This reverts the behavior to .NET Framework - there is now nothing to prevent the handlers from being called multiple times. --- .../src/System/AppContext.cs | 42 +++++-------------- .../RaiseEvent.cs | 8 ---- 2 files changed, 10 insertions(+), 40 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/AppContext.cs b/src/libraries/System.Private.CoreLib/src/System/AppContext.cs index c48d93688fbd3f..6c86be6901e2bb 100644 --- a/src/libraries/System.Private.CoreLib/src/System/AppContext.cs +++ b/src/libraries/System.Private.CoreLib/src/System/AppContext.cs @@ -82,50 +82,28 @@ public static void SetData(string name, object? data) internal static event EventHandler? 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() diff --git a/src/tests/baseservices/exceptions/RaiseAppDomainUnhandledExceptionEvent/RaiseEvent.cs b/src/tests/baseservices/exceptions/RaiseAppDomainUnhandledExceptionEvent/RaiseEvent.cs index aeff4dbd63771a..94f5e4f7422ddc 100644 --- a/src/tests/baseservices/exceptions/RaiseAppDomainUnhandledExceptionEvent/RaiseEvent.cs +++ b/src/tests/baseservices/exceptions/RaiseAppDomainUnhandledExceptionEvent/RaiseEvent.cs @@ -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; @@ -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]