Skip to content

Commit ea721e7

Browse files
tommcdonjkotas
andauthored
Serialize unhandled exception for crash dump analysis when ExceptionHandler.RaiseUnhandledExceptionEvent is called (#117832)
* Serialize unhandled exception for crash dump analysis when ExceptionHandler.RaiseUnhandledExceptionEvent is called * Use cheaper locking mechanism for SerializeCrashInfo * Remove superfluous assignment * Apply suggestions from code review Co-authored-by: Jan Kotas <[email protected]> * Block secondary calls to SerializeCrashInfo until the data has been serialized (prevents early process exit) * Update src/coreclr/nativeaot/System.Private.CoreLib/src/System/RuntimeExceptionHelpers.cs * Update src/coreclr/nativeaot/System.Private.CoreLib/src/System/RuntimeExceptionHelpers.cs --------- Co-authored-by: Jan Kotas <[email protected]>
1 parent 5107b8f commit ea721e7

File tree

2 files changed

+38
-17
lines changed

2 files changed

+38
-17
lines changed

src/coreclr/nativeaot/System.Private.CoreLib/src/System/RuntimeExceptionHelpers.cs

Lines changed: 35 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -192,23 +192,49 @@ public struct ExceptionInformationArray
192192
}
193193

194194
private static ulong s_crashingThreadId;
195+
private static IntPtr s_triageBufferAddress;
196+
private static int s_triageBufferSize;
197+
private static volatile int s_crashInfoPresent;
198+
199+
internal static void SerializeCrashInfo(RhFailFastReason reason, string? message, Exception? exception)
200+
{
201+
int previousState = Interlocked.CompareExchange(ref s_crashInfoPresent, -1, 0);
202+
if (previousState == 0)
203+
{
204+
CrashInfo crashInfo = new();
205+
206+
crashInfo.Open(reason, Thread.CurrentOSThreadId, message ?? GetStringForFailFastReason(reason));
207+
if (exception != null)
208+
{
209+
crashInfo.WriteException(exception);
210+
}
211+
crashInfo.Close();
212+
s_triageBufferAddress = crashInfo.TriageBufferAddress;
213+
s_triageBufferSize = crashInfo.TriageBufferSize;
214+
215+
s_crashInfoPresent = 1;
216+
}
217+
else
218+
{
219+
while (s_crashInfoPresent != 1)
220+
{
221+
// Some other thread is generating the crash info
222+
Thread.Sleep(1);
223+
}
224+
}
225+
}
195226

196227
[DoesNotReturn]
197228
internal static unsafe void FailFast(string? message = null, Exception? exception = null, string? errorSource = null,
198229
RhFailFastReason reason = RhFailFastReason.EnvironmentFailFast,
199230
IntPtr pExAddress = 0, IntPtr pExContext = 0)
200231
{
201-
IntPtr triageBufferAddress = IntPtr.Zero;
202-
int triageBufferSize = 0;
203232
int errorCode = 0;
204233

205234
ulong currentThreadId = Thread.CurrentOSThreadId;
206235
ulong previousThreadId = Interlocked.CompareExchange(ref s_crashingThreadId, currentThreadId, 0);
207236
if (previousThreadId == 0)
208237
{
209-
CrashInfo crashInfo = new();
210-
crashInfo.Open(reason, s_crashingThreadId, message ?? GetStringForFailFastReason(reason));
211-
212238
bool minimalFailFast = (exception == PreallocatedOutOfMemoryException.Instance);
213239
if (!minimalFailFast)
214240
{
@@ -264,17 +290,9 @@ internal static unsafe void FailFast(string? message = null, Exception? exceptio
264290
reporter.Report();
265291
}
266292
#endif
293+
} // !minimalFailFast
267294

268-
if (exception != null)
269-
{
270-
crashInfo.WriteException(exception);
271-
}
272-
}
273-
274-
crashInfo.Close();
275-
276-
triageBufferAddress = crashInfo.TriageBufferAddress;
277-
triageBufferSize = crashInfo.TriageBufferSize;
295+
SerializeCrashInfo(reason, message, minimalFailFast ? null : exception);
278296

279297
// Try to map the failure into a HRESULT that makes sense
280298
errorCode = exception != null ? exception.HResult : reason switch
@@ -310,8 +328,8 @@ internal static unsafe void FailFast(string? message = null, Exception? exceptio
310328
exceptionRecord.NumberParameters = 4;
311329
exceptionRecord.ExceptionInformation[0] = FAST_FAIL_EXCEPTION_DOTNET_AOT;
312330
exceptionRecord.ExceptionInformation[1] = (uint)errorCode;
313-
exceptionRecord.ExceptionInformation[2] = (nuint)triageBufferAddress;
314-
exceptionRecord.ExceptionInformation[3] = (uint)triageBufferSize;
331+
exceptionRecord.ExceptionInformation[2] = (nuint)s_triageBufferAddress;
332+
exceptionRecord.ExceptionInformation[3] = (uint)s_triageBufferSize;
315333

316334
#if TARGET_WINDOWS
317335
Interop.Kernel32.RaiseFailFastException(new IntPtr(&exceptionRecord), pExContext, pExAddress == IntPtr.Zero ? FAIL_FAST_GENERATE_EXCEPTION_ADDRESS : 0);

src/libraries/System.Private.CoreLib/src/System/AppContext.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,9 @@ public static void SetData(string name, object? data)
8787
#endif
8888
internal static void OnUnhandledException(object e)
8989
{
90+
#if NATIVEAOT
91+
RuntimeExceptionHelpers.SerializeCrashInfo(System.Runtime.RhFailFastReason.UnhandledException, (e as Exception)?.Message, e as Exception);
92+
#endif
9093
if (UnhandledException is UnhandledExceptionEventHandler handlers)
9194
{
9295
UnhandledExceptionEventArgs args = new(e, isTerminating: true);

0 commit comments

Comments
 (0)