Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
180c0b1
Implement SetFatalErrorHandler for NativeAOT
AaronRobinsonMSFT Jun 16, 2026
fc2fd84
Implement SetFatalErrorHandler for CoreCLR
AaronRobinsonMSFT Jun 17, 2026
9e102dd
Apply suggestions from code review
AaronRobinsonMSFT Jun 17, 2026
0da0fa6
Use _exit() for SkipDefaultHandler on Unix
AaronRobinsonMSFT Jun 17, 2026
01fe291
Add using declaration for Process in test
AaronRobinsonMSFT Jun 17, 2026
fd85bf0
Simplify test process launch with Process.RunAndCaptureText
AaronRobinsonMSFT Jun 17, 2026
1c4d60c
Address PR feedback: use _Exit, fix IsCrashExitCode, suppress warning
AaronRobinsonMSFT Jun 18, 2026
e27a586
Fix handler invocation on Windows and exclude Mono
AaronRobinsonMSFT Jun 18, 2026
e6eec0a
Address PR feedback: UTF-8 crash log, exit code checks, truncation fix
AaronRobinsonMSFT Jun 18, 2026
6965928
Merge remote-tracking branch 'upstream/main' into set-fatal-error-han…
AaronRobinsonMSFT Jun 19, 2026
6249ab4
Replace managed test handlers with native C++ library
AaronRobinsonMSFT Jun 19, 2026
05e0539
Potential fix for pull request finding
AaronRobinsonMSFT Jun 19, 2026
d48a54e
Move crash log writer abstraction into eepolicy.cpp
AaronRobinsonMSFT Jun 23, 2026
88d4857
Fix HandleFatalStackOverflow: invoke handler after stack trace
AaronRobinsonMSFT Jun 23, 2026
6b1848b
Remove unused SystemNative__Exit entrypoint
AaronRobinsonMSFT Jun 24, 2026
58f269d
Address PR review feedback
AaronRobinsonMSFT Jun 24, 2026
8a47f90
Populate FatalErrorInfo with native exception pointers on Unix
AaronRobinsonMSFT Jun 25, 2026
9f69d40
Move fatal error handler to C++ static with QCall registration
AaronRobinsonMSFT Jun 25, 2026
a9d2d1c
Simplify InvokeFatalErrorHandler to direct call
AaronRobinsonMSFT Jun 25, 2026
3b40c8c
Address PR feedback: fix QCall return type, PAL decorators, remove de…
AaronRobinsonMSFT Jun 25, 2026
d798770
Route stack trace through CrashInfoWriter for callback support
AaronRobinsonMSFT Jun 26, 2026
83a87c4
Surface native exception info/context to the fatal error handler on m…
AaronRobinsonMSFT Jun 30, 2026
56ce69a
Refactor fatal error property storage into common core + platform module
AaronRobinsonMSFT Jul 6, 2026
790b319
Fix duplicate crash log and stack-overflow header in fatal error path
AaronRobinsonMSFT Jul 7, 2026
a65444a
Store hardware-exception records per-fault to survive nested faults
AaronRobinsonMSFT Jul 7, 2026
ad36176
Align hardware-exception records within the per-fault buffer
AaronRobinsonMSFT Jul 7, 2026
9ab5194
Use InlineArray16 for crash log fragment storage
AaronRobinsonMSFT Jul 7, 2026
5ec609f
Address PR review feedback
AaronRobinsonMSFT Jul 8, 2026
baa5e41
Clarify comment on FatalErrorPropertyGetter regarding ownership of data
AaronRobinsonMSFT Jul 8, 2026
9a074eb
Address PR review feedback
AaronRobinsonMSFT Jul 8, 2026
2abb2df
Merge remote-tracking branch 'upstream/main' into set-fatal-error-han…
AaronRobinsonMSFT Jul 9, 2026
a3ce5f0
Address PR review feedback
AaronRobinsonMSFT Jul 9, 2026
01e4dc1
Stage 1: surface fault IP to fatal error handler (managed path)
AaronRobinsonMSFT Jul 10, 2026
323a39f
Stage 2: route genuinely-unmanaged fatal faults to the fatal error ha…
AaronRobinsonMSFT Jul 10, 2026
9e1739e
Stage 2: route genuinely-unmanaged fatal faults to the fatal error ha…
AaronRobinsonMSFT Jul 10, 2026
401175a
WIP
AaronRobinsonMSFT Jul 10, 2026
f28cd9f
Merge branch 'main' into set-fatal-error-handler
AaronRobinsonMSFT Jul 12, 2026
e011455
Address review feedback: synchronize native fatal handler pointer, po…
AaronRobinsonMSFT Jul 13, 2026
3b16843
Enhance comments in fatal error handling to clarify encoder behavior …
AaronRobinsonMSFT Jul 17, 2026
1a608d4
Refactor crash log handling to use a single managed string, improving…
AaronRobinsonMSFT Jul 20, 2026
f72811e
Serialize concurrent fatal error handling to ensure only the first fa…
AaronRobinsonMSFT Jul 24, 2026
7960de5
Merge remote-tracking branch 'upstream/main' into set-fatal-error-han…
AaronRobinsonMSFT Jul 24, 2026
2fa3051
Install fatal error handling header
AaronRobinsonMSFT Jul 27, 2026
cd46bf2
Make C compliant
AaronRobinsonMSFT Jul 27, 2026
5871c68
Handle native fatal exceptions in CoreCLR
AaronRobinsonMSFT Jul 29, 2026
46a4925
Invoke fatal error handler for SIGABRT
AaronRobinsonMSFT Jul 30, 2026
0b0e3ad
Merge upstream/main into set-fatal-error-handler
AaronRobinsonMSFT Jul 31, 2026
2fba4fa
Split TerminateProcess interop declarations
AaronRobinsonMSFT Jul 31, 2026
df78676
Refactor fatal error handling: remove previous unhandled exception fi…
AaronRobinsonMSFT Jul 31, 2026
b67696a
Reserve fatal error handler return values
AaronRobinsonMSFT Jul 31, 2026
5bd6d69
Invoke NativeAOT fatal handlers from native code
AaronRobinsonMSFT Aug 3, 2026
72669ae
Cover CoreCLR native utility threads in the fatal error handler
AaronRobinsonMSFT Aug 4, 2026
b6190a6
Ensure process termination in InvokeFatalErrorHandler on spurious wakeup
AaronRobinsonMSFT Aug 4, 2026
164f4a2
Expose on-demand crash reports to fatal error handlers.
lateralusX Aug 6, 2026
182bdb9
Initialize crash reporter before publishing handler
lateralusX Aug 6, 2026
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
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,7 @@
<Compile Include="$(MSBuildThisFileDirectory)..\nativeaot\Runtime.Base\src\System\Runtime\ExceptionIDs.cs" />
<Compile Include="$(MSBuildThisFileDirectory)..\nativeaot\Runtime.Base\src\System\Runtime\StackFrameIterator.cs" />
<Compile Include="$(BclSourcesRoot)\System\Runtime\ExceptionServices\AsmOffsets.cs" />
<Compile Include="$(BclSourcesRoot)\System\Runtime\ExceptionServices\ExceptionHandling.CoreCLR.cs" />
<Compile Include="$(BclSourcesRoot)\System\Runtime\ExceptionServices\InternalCalls.cs" />
<Compile Include="$(BclSourcesRoot)\System\Runtime\GCSettings.CoreCLR.cs" />
<Compile Include="$(BclSourcesRoot)\System\Runtime\JitInfo.CoreCLR.cs" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

namespace System.Runtime.ExceptionServices
{
public static partial class ExceptionHandling
{
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "ExceptionHandling_TrySetFatalErrorHandler")]
[return: MarshalAs(UnmanagedType.U1)]
private static partial bool TrySetFatalErrorHandler(IntPtr handler);
}
}
54 changes: 27 additions & 27 deletions src/coreclr/debug/crashreport/inproccrashreporter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ class ThreadEnumerationContext
size_t methodNameScratchSize,
uint64_t crashingTid,
uint32_t frameLimitPerThread,
void* signalContext)
const void* signalContext)
{
Init(writer, consoleWriter, moduleInfoCallback, moduleTable, formatter, methodNameScratch, methodNameScratchSize, crashingTid, frameLimitPerThread, signalContext);
}
Expand All @@ -237,7 +237,7 @@ class ThreadEnumerationContext
size_t methodNameScratchSize,
uint64_t crashingTid,
uint32_t frameLimitPerThread,
void* signalContext)
const void* signalContext)
{
m_frameContext.jsonWriter = writer;
m_frameContext.consoleWriter = consoleWriter;
Expand Down Expand Up @@ -310,7 +310,7 @@ class ThreadEnumerationContext
void EndCurrentJsonThreadBlock();

FrameContext m_frameContext;
void* m_signalContext;
const void* m_signalContext;
size_t m_threadCount;
uint64_t m_crashingTid;
uint32_t m_currentThreadFrameCount;
Expand Down Expand Up @@ -366,7 +366,7 @@ class InProcCrashReporter
// Signal-path report generation, invoked by the PAL fatal-signal dispatcher.
bool CreateReport(
int signal,
void* context,
const void* context,
bool serialize);

// On-demand report generation. Runs the same emit core as the signal path
Expand All @@ -375,7 +375,7 @@ class InProcCrashReporter
bool CreateReport(
InProcCrashReportOutputFormat outputFormat,
int signal,
void* context,
const void* context,
InProcCrashReportOutputCallback outputCallback,
void* callbackContext);

Expand All @@ -393,14 +393,14 @@ class InProcCrashReporter
InProcCrashReporter& operator=(const InProcCrashReporter&) = delete;

void EmitSynthesizedCrashThread(
void* context,
const void* context,
bool walkStack);

void EmitStackOverflowCrashThread();

void EmitThreads(
InProcCrashReportCrashKind crashKind,
void* context);
const void* context);

void BeginConsoleReport(int signal);
bool EndConsoleReport();
Expand Down Expand Up @@ -453,20 +453,20 @@ class CrashReportHelpers

static void WriteRegistersToJson(
SignalSafeJsonWriter* writer,
void* context);
const void* context);

static uint64_t GetInstructionPointer(
void* context);
const void* context);

static uint64_t GetStackPointer(
void* context);
const void* context);

static uint64_t GetFramePointer(
void* context);
const void* context);

static void WriteCrashSiteFrameToJson(
SignalSafeJsonWriter* writer,
void* context);
const void* context);

static void BuildMethodName(
char* buffer,
Expand Down Expand Up @@ -529,7 +529,7 @@ class CrashReportHelpers
static void BeginJsonStackFrames(
SignalSafeJsonWriter* jsonWriter,
bool writeCrashSiteFrame,
void* signalContext);
const void* signalContext);

static void EndJsonStackFrames(
SignalSafeJsonWriter* jsonWriter);
Expand Down Expand Up @@ -587,7 +587,7 @@ class CrashReportHelpers
bool
InProcCrashReporter::CreateReport(
int signal,
void* context,
const void* context,
bool serialize)
{
if (!serialize)
Expand Down Expand Up @@ -664,7 +664,7 @@ bool
InProcCrashReporter::CreateReport(
InProcCrashReportOutputFormat outputFormat,
int signal,
void* context,
const void* context,
InProcCrashReportOutputCallback outputCallback,
void* callbackContext)
{
Expand Down Expand Up @@ -722,7 +722,7 @@ InProcCrashReporter::CreateReport(
void
InProcCrashReporter::EmitThreads(
InProcCrashReportCrashKind crashKind,
void* context)
const void* context)
{
m_jsonWriter.OpenArray("threads");
if (crashKind == InProcCrashReportCrashKind::StackOverflow)
Expand Down Expand Up @@ -971,7 +971,7 @@ bool
InProcCrashReportCreateReport(
InProcCrashReportOutputFormat outputFormat,
int signal,
void* context,
const void* context,
InProcCrashReportOutputCallback outputCallback,
void* callbackContext)
{
Expand Down Expand Up @@ -1170,7 +1170,7 @@ CrashReportHelpers::AppendString(
void
CrashReportHelpers::WriteRegistersToJson(
SignalSafeJsonWriter* writer,
void* context)
const void* context)
{
uint64_t ipValue = GetInstructionPointer(context);
uint64_t spValue = GetStackPointer(context);
Expand Down Expand Up @@ -1247,47 +1247,47 @@ CrashReportHelpers::WriteRegistersToJson(

uint64_t
CrashReportHelpers::GetInstructionPointer(
void* context)
const void* context)
{
if (context == nullptr)
{
return 0;
}

ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context);
const ucontext_t* ucontext = reinterpret_cast<const ucontext_t*>(context);
return CRASH_MCREG_PC(ucontext);
}

uint64_t
CrashReportHelpers::GetStackPointer(
void* context)
const void* context)
{
if (context == nullptr)
{
return 0;
}

ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context);
const ucontext_t* ucontext = reinterpret_cast<const ucontext_t*>(context);
return CRASH_MCREG_SP(ucontext);
}

uint64_t
CrashReportHelpers::GetFramePointer(
void* context)
const void* context)
{
if (context == nullptr)
{
return 0;
}

ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context);
const ucontext_t* ucontext = reinterpret_cast<const ucontext_t*>(context);
return CRASH_MCREG_FP(ucontext);
}

void
CrashReportHelpers::WriteCrashSiteFrameToJson(
SignalSafeJsonWriter* writer,
void* context)
const void* context)
{
uint64_t ipValue = GetInstructionPointer(context);
uint64_t spValue = GetStackPointer(context);
Expand Down Expand Up @@ -1619,7 +1619,7 @@ void
CrashReportHelpers::BeginJsonStackFrames(
SignalSafeJsonWriter* jsonWriter,
bool writeCrashSiteFrame,
void* signalContext)
const void* signalContext)
{
if (jsonWriter == nullptr)
{
Expand Down Expand Up @@ -1993,7 +1993,7 @@ ThreadEnumerationContext::EnumerateThreads(

void
InProcCrashReporter::EmitSynthesizedCrashThread(
void* context,
const void* context,
bool walkStack)
{
uint64_t crashingTid = static_cast<uint64_t>(minipal_get_current_thread_id());
Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/debug/crashreport/inproccrashreporter.h
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ void InProcCrashReportInitializeServices(const InProcCrashReporterServicesSettin
bool InProcCrashReportCreateReport(
InProcCrashReportOutputFormat outputFormat,
int signal,
void* context,
const void* context,
InProcCrashReportOutputCallback outputCallback,
void* callbackContext);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -307,7 +307,7 @@ internal static Exception GetClasslibException(ExceptionIDs id, IntPtr address)
Exception? e = null;
try
{
e = ((delegate*<ExceptionIDs, Exception>)pGetRuntimeExceptionFunction)(id);
e = ((delegate*<ExceptionIDs, IntPtr, Exception>)pGetRuntimeExceptionFunction)(id, address);
}
catch when (true)
{
Expand Down Expand Up @@ -362,7 +362,8 @@ internal static Exception GetClasslibExceptionFromEEType(ExceptionIDs id, Method
Exception? e = null;
try
{
e = ((delegate*<ExceptionIDs, Exception>)pGetRuntimeExceptionFunction)(id);
// The MethodTable-based lookup path has no faulting instruction pointer to surface.
e = ((delegate*<ExceptionIDs, IntPtr, Exception>)pGetRuntimeExceptionFunction)(id, IntPtr.Zero);
}
catch when (true)
{
Expand Down Expand Up @@ -424,8 +425,9 @@ public static void FailedAllocation(MethodTable* pEEType, bool fIsOverflow)
// There are only a few cases where this happens now (the fast allocation helpers), so we limit the
// exception types that MRT will return.
[RuntimeExport("GetRuntimeException")]
public static Exception GetRuntimeException(ExceptionIDs id)
public static Exception GetRuntimeException(ExceptionIDs id, IntPtr faultingIP)
{
_ = faultingIP;
switch (id)
{
case ExceptionIDs.OutOfMemory:
Expand Down
Loading
Loading